Giới thiệu
Trong vài tuần qua, tôi phải đối mặt với một nhiệm vụ lặp đi lặp lại: mỗi tuần, một loạt các tệp TSV cần được nhập và tải vào cơ sở dữ liệu RDS. Việc duy trì một cơ sở dữ liệu đầy đủ cho hoạt động đơn giản này cảm thấy quá thừa thãi và quy trình này rất tốn thời gian.
Vì vậy, tôi đã quyết định tìm hiểu DuckDB, một cơ sở dữ liệu phân tích trong quá trình hoạt động được biết đến với hiệu suất và sự đơn giản.
💡 Ý tưởng là xử lý các tệp TSV trực tiếp trong môi trường serverless, biến đổi chúng bằng các truy vấn SQL và lưu trữ kết quả mà không cần chạy một cơ sở dữ liệu cố định.
🦆 DuckDB Là Gì?
DuckDB là một cơ sở dữ liệu phân tích mã nguồn mở, thường được mô tả như "SQLite cho phân tích". Nó được tối ưu hóa đặc biệt cho các truy vấn phân tích và có khả năng quét các tập dữ liệu lớn một cách hiệu quả.
Một trong những tính năng nổi bật của DuckDB là khả năng đọc các định dạng lưu trữ cột như Parquet trực tiếp từ các tệp cục bộ, bucket S3 hoặc các điểm cuối HTTP. DuckDB quét và tổng hợp dữ liệu một cách động mà không cần tải toàn bộ tập dữ liệu vào bộ nhớ, điều này đặc biệt hữu ích trong các môi trường serverless, nơi mà việc sử dụng bộ nhớ và tính toán ảnh hưởng trực tiếp đến chi phí.
Khi kết hợp với AWS Lambda, thay vì sử dụng các truy vấn Athena, các phiên bản RDS, hoặc các quy trình ETL phức tạp, DuckDB cho phép bạn chạy các khối lượng công việc phân tích theo yêu cầu trong một hàm Lambda, chỉ phải trả cho những gì bạn thực sự sử dụng. Các dịch vụ AWS hiện có như Athena hoặc RDS có thể đáp ứng nhu cầu tương tự, nhưng chúng có các mô hình mở rộng và chiến lược giá cả khác nhau. Athena, ví dụ, tính phí theo byte đã quét và giới thiệu độ trễ truy vấn, trong khi RDS yêu cầu bạn duy trì một cơ sở dữ liệu luôn hoạt động.
🤯 Thách Thức Khi Sử Dụng DuckDB Trên Lambda
Để cấu hình Lambda của tôi, tôi dựa vào Terraform để quản lý hạ tầng. Tuy nhiên, tôi nhanh chóng gặp phải một vấn đề lớn: DuckDB là một thư viện đã biên dịch.
Điều này có nghĩa là bạn không thể chỉ đơn giản là pip install duckdb cục bộ và tải lên thông qua Terraform. Nếu nhị phân chưa được biên dịch cho môi trường runtime của Lambda, hàm sẽ không thể nhập nó. Việc nén mã thường không đủ, do sự không tương thích ABI và sự khác biệt hệ điều hành.
Để khắc phục điều này, tôi đã phải thiết lập một container Docker, xây dựng DuckDB bên trong nó, sao chép các tệp kết quả về máy của tôi, nén chúng và sau đó tải mọi thứ lên Lambda.
Cách tiếp cận này hoạt động, nhưng không lý tưởng cho các dự án nhỏ hoặc khi bạn chỉ cần nhanh chóng chạy một Lambda. Bạn buộc phải đối phó với các vấn đề như cài đặt Docker và thiết lập quy trình xây dựng container, điều này làm tăng đáng kể độ phức tạp.
✅ Giải Pháp
Vì vậy, tôi quyết định tạo các layers Lambda đã được biên dịch sẵn cho mỗi kiến trúc, phiên bản Python và phiên bản DuckDB, sau đó làm cho chúng công khai.
Một layer Lambda là một cách tiện lợi để đóng gói và chia sẻ các phụ thuộc giữa nhiều hàm Lambda mà không cần bao gồm chúng trong mỗi gói triển khai. Điều này hoàn toàn loại bỏ nhu cầu xây dựng cục bộ, vì vậy bất kỳ ai cũng có thể sử dụng DuckDB mà không cần lặp lại cùng một quy trình thiết lập tẻ nhạt.
Các layer này:
- ✅ Được biên dịch sẵn cho mọi phiên bản runtime Python được hỗ trợ bởi Lambda (3.8 → 3.13).
- ✅ Hỗ trợ cả hai kiến trúc (x86_64 và arm64).
- ✅ Có sẵn ở tất cả các vùng AWS.
- ✅ Dễ dàng gắn liền với Lambda của bạn mà không làm tăng kích thước gói triển khai.
Thêm DuckDB vào một hàm Lambda đơn giản như gắn một layer Lambda với ARN của nó:
aws lambda update-function-configuration \
--function-name your-function-name \
--layers LAYER_ARN
Sau đó, bên trong handler của bạn:
import duckdb
def lambda_handler(event, context):
conn = duckdb.connect(":memory:")
result = conn.execute("SELECT 'Hello from DuckDB!' AS msg").fetchall()
return {"statusCode": 200, "body": result[0][0]}
Khi layer được gắn, DuckDB ngay lập tức có sẵn trong hàm Lambda của bạn, loại bỏ nhu cầu phải xây dựng từ mã nguồn hoặc lo lắng về sự không tương thích kiến trúc.
Các layer này giúp phân tích serverless trở nên dễ tiếp cận: các tác vụ trước đây yêu cầu RDS, Athena hoặc quy trình ETL phức tạp giờ đây có thể được xử lý hoàn toàn trong Lambda.
💙 Dự án này là mã nguồn mở. Bạn có thể tìm thấy tất cả các ARN layer và hướng dẫn sử dụng trên GitHub.
👉🏼 Quay Lại Vấn Đề Ban Đầu
Vấn đề ban đầu mà tôi muốn giải quyết khá đơn giản: mỗi tuần tôi phải lấy một tập hợp các tệp TSV và nhập chúng vào một cơ sở dữ liệu MySQL được lưu trữ trên RDS.
Với DuckDB, quy trình công việc này trở nên đáng ngạc nhiên đơn giản. Khi các tệp được tải xuống và có sẵn cục bộ trong thư mục /tmp của Lambda, DuckDB có thể vừa đọc chúng trực tiếp vừa đẩy dữ liệu vào MySQL bằng hệ thống mở rộng của nó.
Dưới đây là phần cốt lõi của nó:
import duckdb
def handler(event, context):
# Kết nối với DuckDB trong bộ nhớ
con = duckdb.connect(database=':memory:')
# Cài đặt và tải mở rộng MySQL
con.install_extension("mysql")
con.load_extension("mysql")
# Gắn kết với cơ sở dữ liệu MySQL mục tiêu
con.execute("""
ATTACH 'host=... user=... password=... port=... database=...' AS mysql (TYPE mysql);
""")
con.execute("USE mysql;")
# Ghi trực tiếp tệp TSV vào một bảng
con.execute("""
CREATE TABLE users AS
SELECT * FROM read_csv('/tmp/users.txt', header=true, delim='\\t');
""")
# Ví dụ truy vấn
result = con.execute("SELECT COUNT(*) FROM users").fetchone()[0]
return {
"statusCode": 200,
"body": f"Users imported: {result}"
}
Kết Luận
Làm việc với DuckDB trong AWS Lambda có thể cảm thấy khó khăn lúc đầu do các vấn đề về nhị phân và khả năng tương thích nền tảng. Nhưng với các layer đã được biên dịch sẵn, toàn bộ quy trình trở nên đơn giản hơn nhiều: bạn có thể tập trung vào việc viết logic Lambda của mình thay vì lo lắng về cách xây dựng và đóng gói DuckDB.
Đối với trường hợp sử dụng của tôi, điều này có nghĩa là từ một quy trình xây dựng Docker thủ công và nén tệp đến một triển khai Terraform đơn giản với một layer sẵn sàng sử dụng. Hy vọng rằng, bằng cách làm cho các layer này trở nên công khai, những người khác có thể tiết kiệm thời gian và sự thất vọng tương tự.
Dự án này cũng tồn tại cho NodeJS, nhờ sáng kiến tuyệt vời của tobilg, bạn có thể tìm thấy nó tại đây.
⭐ Hãy đánh dấu repo, thử nghiệm và đừng ngần ngại mở một PR!