Data Inlining in DuckLake: Unlocking Streaming for Data Lakes
Bài tóm tắt DuckDB Labs 2026 3. Quy mô lớn Độ khó: Trung bình
DuckDB Labs · 2026 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc
Bài của nhà cung cấp quảng bá tính năng của chính họ; benchmark so với Iceberg do họ tự dựng. Mọi nhận định là theo DuckDB Labs.
Bối cảnh
- Data lake (Iceberg, Hudi, Delta) lưu dữ liệu bằng Parquet và metadata cũng bằng file (JSON, Avro) trên object storage. Mỗi lần ghi nhỏ tạo một file dữ liệu mới và cập nhật metadata.
- Với streaming (nhiều lần chèn nhỏ, liên tục), đó là "small files problem": 1.000 lần chèn mỗi giây là 1.000 file nhỏ; query phải duyệt ngày càng nhiều metadata để biết đọc file nào; hoá đơn S3/GCS tăng. Ví dụ của bài: 100 lần chèn một dòng vào Iceberg qua
pyicebergsinh 100 file Parquet và hơn 300 file metadata. - Cách chữa quen thuộc là compaction định kỳ gộp file nhỏ. Nhưng nó không chữa lúc ghi (vẫn trả tiền tạo file nhỏ), chưa chạy thì query vẫn chậm, và khi chạy thì chiếm tài nguyên.
Thay đổi chính
- DuckLake dùng một database làm catalog (SQLite, Postgres...). Thay đổi nhỏ hơn ngưỡng (mặc định 10 dòng, chỉnh được theo global/schema/bảng) được ghi thẳng vào catalog thay vì thành file Parquet:
- Chèn: vào bảng inlined trong catalog, kèm
row_id,begin_snapshot,end_snapshotđể giữ time travel. - Xoá dòng còn inline: chỉ đặt
end_snapshot. Xoá dòng đã nằm trong Parquet: ghi (file_id, row_id, snapshot) vào bảng xoá inline, không viết lại file, không tạo file xoá. - Cập nhật = xoá + chèn.
- Chèn: vào bảng inlined trong catalog, kèm
- Lúc query, DuckLake ghép dữ liệu inline với file Parquet có sẵn.
- Flush (riêng, hoặc trong
CHECKPOINTcùng expire snapshot, gộp file, dọn dẹp) đổ dữ liệu inline ra một file Parquet gom lại.
Kết quả (theo DuckDB Labs)
- Benchmark: một bảng 23 cột, 100 dòng/giây theo 10 lô × 10 dòng, mô phỏng 50 phút (300.000 dòng, 30.000 lô); catalog là RDS Postgres, dữ liệu trên S3 cùng region.
- Chèn nhanh hơn 5,2 lần (round-trip ghi vào Postgres rẻ hơn ghi một file Parquet lên S3 cho mỗi lô).
- Aggregation nhanh hơn 926 lần: không inline thì mỗi query mở 30.000 file trên S3.
- Checkpoint nhanh hơn 14,5 lần: gộp 30.000 file so với đổ một lần từ catalog ra một file.
- So với Iceberg (
pyiceberg+ Apache Polaris), phải thu nhỏ còn 100 giây vì Iceberg chạy quá lâu: chèn nhanh hơn 105 lần, aggregation 923 lần, checkpoint 189 lần. Lý do theo bài: Iceberg thêm một bước REST (Polaris) và mô hình snapshot (manifest + manifest-list + metadata JSON) ghi khoảng 4 file S3 mỗi lô, DuckLake inline thì không ghi file nào. - Bài thừa nhận có thể giảm vấn đề bằng cách đệm phía client hay chèn lô lớn hơn, nhưng theo họ cách đó hy sinh ACID và hỗ trợ nhiều người ghi.
Vì sao
- Object storage rẻ cho file lớn nhưng đắt cho thao tác nhỏ (mỗi PUT/GET là chi phí cố định và một round-trip). Database thì đã tối ưu hàng chục năm cho đọc/ghi nhỏ. Inline là dùng đúng công cụ cho từng cỡ ghi: nhỏ vào DB, lớn ra Parquet (Batching và khấu hao round-trip, Tách compute khỏi storage).
- Gom lô ở phía server (flush khi đủ) giữ được ngữ nghĩa giao dịch, khác với gom ở phía client (Pipeline dữ liệu và analytics).
Bài học cho SWE
- Khi đẩy stream vào lake, đếm số file và số thao tác object storage mỗi lô, không chỉ số dòng.
- Có chỗ trung gian rẻ cho ghi nhỏ (bảng trong DB, WAL, buffer bền) rồi mới đổ thành file lớn là mẫu chung: so với WarpStream gom batch trước khi PUT.
- Thận trọng với benchmark nhà cung cấp so với đối thủ: cấu hình đối thủ (REST catalog, cỡ lô) quyết định phần lớn khoảng cách.
Liên quan
#DuckLake#Data lake#Small files problem#Parquet#Iceberg#Catalog database#Data inlining#Compaction#Streaming ingestion#Time travel
Được nhắc tới trong
Công ty (1)