- Quack cung cấp giao tiếp giữa các instance DuckDB, cho phép mô hình client-server và nhiều trình ghi đồng thời dùng cùng một cơ sở dữ liệu
- Trong khi vẫn giữ kiến trúc in-process, DuckDB xử lý việc đồng bộ trạng thái cần thiết khi nhiều tiến trình cùng sửa một tệp thông qua giao thức từ xa này
- Quack là giao thức yêu cầu-phản hồi dựa trên HTTP, dùng tuần tự hóa
application/duckdb và xác thực bằng token, với cổng mặc định là 9494
- Trong benchmark, Quack đã truyền 60 triệu dòng trong 4,94 giây, và ở bài kiểm tra append nhỏ cũng đạt khoảng 5.434 tx/s với 8 luồng
- Quack dự kiến tích hợp DuckLake, Catalog server từ xa, tự động cài đặt·nạp, mở rộng giao thức và giao thức sao chép, với mục tiêu phát hành production vào thời điểm DuckDB v2.0
Mục đích và bối cảnh của Quack
- Quack là một giao thức từ xa cho phép các instance DuckDB giao tiếp với nhau, giúp chạy DuckDB trong mô hình client-server và cho phép nhiều trình ghi đồng thời sử dụng cùng một cơ sở dữ liệu
- Từ năm 2019, DuckDB đã nhấn mạnh kiến trúc in-process; cách vận hành bằng các lời gọi API mức thấp mà không cần server hay giao thức riêng rất phù hợp với các tác vụ khoa học dữ liệu tương tác như notebook Python và việc cung cấp chức năng SQL trong ứng dụng
- Để nhiều tiến trình cùng sửa một tệp cơ sở dữ liệu DuckDB một lúc, cần đồng bộ rất nhiều trạng thái mà DuckDB giữ trong bộ nhớ chính giữa các tiến trình
- Trước đây đã có các cách vòng như tiến trình RPC riêng, các dự án dùng Arrow Flight SQL protocol, giao thức riêng của MotherDuck, hoặc kết hợp PostgreSQL với pg_duckdb như “EleDucken”
- Để mở rộng DuckDB thành công cụ xử lý dữ liệu đa dụng, ngoài khả năng in-process, một giao thức client-server có thể mở ra các trường hợp sử dụng mới
Cách dùng Quack
- Trong Quack, từ hai instance DuckDB trở lên có thể giao tiếp với nhau, và DuckDB đóng cả vai trò client lẫn server
- Hai instance có thể nằm trên các máy khác nhau, ở vị trí từ xa, hoặc ở các cửa sổ terminal khác nhau trên cùng một laptop
- Extension Quack hiện có trong kho
core_nightly, và có thể dùng trên phiên bản phát hành hiện tại là DuckDB v1.5.2
- Ở instance DuckDB phía server, sau khi cài đặt và nạp Quack thì gọi
quack_serve; ví dụ dùng quack:localhost và token = 'super_secret'
INSTALL quack FROM core_nightly;
LOAD quack;
CALL quack_serve(
'quack:localhost',
token = 'super_secret'
);
CREATE TABLE hello AS
FROM VALUES ('world') v(s);
- Ở instance DuckDB phía client cũng cài đặt và nạp Quack, đặt token bằng
CREATE SECRET, rồi kết nối instance từ xa bằng ATTACH 'quack:localhost' AS remote;
INSTALL quack FROM core_nightly;
LOAD quack;
CREATE SECRET (
TYPE quack,
TOKEN 'super_secret'
);
ATTACH 'quack:localhost' AS remote;
FROM remote.hello;
- Với cấu hình này, DuckDB #2 có thể truy vấn giá trị
world từ bảng từ xa hello
- Cũng có thể sao chép dữ liệu từ instance cục bộ sang instance từ xa; trong ví dụ, tạo bảng
remote.hello2 từ DuckDB #2 rồi kiểm tra bằng FROM hello2; trên DuckDB #1
- Với truy vấn phức tạp hoặc tập dữ liệu lớn, có thể kiểm soát tốt hơn phần nào chạy ở phía từ xa bằng hàm
query, vốn gửi nguyên truy vấn sang phía từ xa
FROM remote.query(
'SELECT s FROM hello'
);
Thiết kế giao thức
-
Dựa trên HTTP
- Quack được xây trực tiếp trên HTTP, vốn đã trở thành tầng giao thức tiêu chuẩn trên thực tế phía trên TCP và các tầng thấp hơn
- Stack HTTP đã được tối ưu hiệu quả cho việc truyền luồng thông điệp, và nếu triển khai tốt thì overhead thấp
- Cách xử lý HTTP trong các lĩnh vực như cân bằng tải, xác thực, tường lửa, phát hiện xâm nhập đã rất quen thuộc
- Nhờ dùng HTTP, bản phân phối DuckDB-Wasm cũng có thể dùng Quack một cách native
- DuckDB chạy trong trình duyệt có thể kết nối trực tiếp bằng Quack tới một instance DuckDB chạy trên máy chủ EC2
-
Mô hình yêu cầu-phản hồi
- Tương tác của Quack luôn hoạt động theo mô hình yêu cầu-phản hồi do client khởi xướng
- Thông điệp bao gồm yêu cầu kết nối để xác thực bằng token, yêu cầu thực thi truy vấn, trả về phần đầu của phản hồi, và các thông điệp fetch tiếp theo để lấy kết quả lớn
- Kết quả lớn có thể được lấy song song từ nhiều luồng
-
Tuần tự hóa
- Yêu cầu và phản hồi được mã hóa bằng MIME type mới là
application/duckdb
- Cách mã hóa này tận dụng các primitive tuần tự hóa nội bộ của DuckDB cho những cấu trúc phức tạp như kiểu dữ liệu và tập kết quả
- Các primitive này cũng đã được dùng trong các tệp WAL của DuckDB nhiều năm qua, và đã được tối ưu cũng như kiểm chứng đáng kể
-
Mã hóa và cách phơi bày dịch vụ
- Theo mặc định, khi khởi động server, Quack sẽ tạo token xác thực ngẫu nhiên, và client phải cung cấp token này
- Mặc định, server Quack chỉ bind vào
localhost, nhưng có thể ghi đè hành vi này
- Mặc định Quack không dùng SSL, vì việc thêm hạ tầng và phụ thuộc đó chỉ để phục vụ giao tiếp
localhost được xem là không phù hợp
- Không khuyến nghị mở trực tiếp endpoint DuckDB Quack ra Internet
- Nếu cần phơi Quack lên web, khuyến nghị mạnh mẽ dùng một endpoint HTTP phổ biến như nginx, để proxy đó xử lý SSL bằng Let’s Encrypt hoặc tương tự
- Client Quack mặc định giả định rằng SSL được bật cho các kết nối không phải cục bộ, nhưng có thể ghi đè hành vi này
- Xem các thiết lập liên quan trong tài liệu reverse proxy
-
Tối ưu số lần round-trip
- Quack được thiết kế để giảm số lần round-trip của giao thức cần cho một truy vấn
- Sau khi kết nối, một truy vấn có thể được xử lý trong một round-trip duy nhất, có lợi trong môi trường nhạy cảm với độ trễ
- Việc truyền phản hồi lớn cũng được tối ưu, và nhóm DuckDB cho rằng hiện Quack là cách nhanh nhất để truyền bảng qua socket
- Benchmark cho thấy có thể truyền hàng triệu dòng chỉ trong vài giây
-
Xác thực và phân quyền
- Quack thiết kế mô hình xác thực và phân quyền phù hợp với triết lý mở rộng của DuckDB
- Mặc định có phương thức xác thực cơ bản và phân quyền mặc định không giới hạn, nhưng cả hai đều có thể thay bằng mã do người dùng cung cấp
- Khi server khởi động, nó tạo token xác thực ngẫu nhiên, và client cung cấp chuỗi xác thực khi kết nối
- Server gọi callback xác thực; callback mặc định sẽ so sánh token client cung cấp với token mà server đã tạo
- Có thể thay callback xác thực bằng cấu hình để dùng tra cứu LDAP, đọc tệp văn bản, hay bất kỳ logic nào khác
- Hàm phân quyền cũng có thể thay thế; hàm mặc định cho phép mọi yêu cầu
- Hàm phân quyền do người dùng viết có thể kiểm tra từng truy vấn mà client muốn chạy và quyết định dựa trên chuỗi xác thực đã dùng trước đó
- Các callback kiểu này thậm chí có thể được viết bằng SQL macro thông thường
-
Cổng mặc định
- Theo mặc định, server Quack lắng nghe trên cổng
9494
94 là con số gợi nhớ tới năm 1994, năm Netscape Navigator ra mắt
Benchmark
- Benchmark được thực hiện trên máy ảo AWS chạy Ubuntu on Arm
- Loại instance là m8g.2xlarge, có 8 vCPU, 32GB RAM, và băng thông mạng “tối đa 15Gbps”
- Mục tiêu là tái hiện một kịch bản thực tế nơi client và server ở cùng data center nhưng trên các máy khác nhau
- Hai instance được đặt trong cùng availability zone, và thời gian ping trung bình khoảng 0,280ms
-
Truyền dữ liệu lớn
- Benchmark đầu tiên đo tác vụ truyền dữ liệu lớn với rất nhiều dòng qua giao thức cơ sở dữ liệu
- Các đối tượng so sánh là Quack, giao thức PostgreSQL, và giao thức Arrow Flight SQL
- Arrow Flight được cung cấp thông qua máy chủ GizmoSQL dùng DuckDB ở bên trong
- Dữ liệu được truyền từ bảng TPC-H
lineitem với số lượng dòng tăng dần, đo tới tối đa 60 triệu dòng
- 60 triệu dòng tương đương 76GB ở định dạng CSV
- Mỗi kết quả được báo cáo bằng median wall-clock time của 5 lần chạy
- Các kết quả chính như sau
- 100k dòng: DuckDB Quack
0.07 s, Arrow Flight 0.07 s, PostgreSQL 0.20 s
- 1M dòng: DuckDB Quack
0.24 s, Arrow Flight 0.38 s, PostgreSQL 2.20 s
- 10M dòng: DuckDB Quack
0.89 s, Arrow Flight 2.90 s, PostgreSQL 25.64 s
- 60M dòng: DuckDB Quack
4.94 s, Arrow Flight 17.40 s, PostgreSQL 158.37 s
- Quack truyền 60 triệu dòng trong dưới 5 giây, cho thấy hiệu năng mạnh trong việc chuyển các tập kết quả lớn
- Ngay cả Arrow Flight SQL vốn hướng mục tiêu chuyên biệt cũng không theo kịp Quack trong kết quả này, còn giao thức theo dòng của PostgreSQL nhìn chung bất lợi hơn
- Client PostgreSQL tiêu chuẩn không song song hóa việc đọc trên nhiều luồng, trong khi Quack và Arrow thì có thể
- PostgreSQL client của DuckDB cũng có thể đọc song song trong một số trường hợp
-
Ghi nhỏ
- Benchmark thứ hai đo tác vụ append nhỏ
- Đây tương ứng với tình huống tập trung các ghi nhỏ, như cấu hình gom dữ liệu observability về một instance DuckDB trung tâm
- Đây là bài test bất lợi cho các giao thức cần nhiều lần round-trip client-server để hoàn tất một giao dịch đơn lẻ
- Một bảng rỗng có cùng cấu trúc với TPC-H
lineitem được tạo ra, rồi chèn từng dòng giá trị ngẫu nhiên, mỗi dòng trong một giao dịch INSERT riêng
- Bài test chạy trong 5 giây với số luồng song song tăng dần, lặp lại 5 lần và báo cáo median số giao dịch trên giây
- Các kết quả chính như sau
- 1 luồng: DuckDB Quack
1,038 tx/s, Arrow Flight 469 tx/s, PostgreSQL 839 tx/s
- 2 luồng: DuckDB Quack
1,956 tx/s, Arrow Flight 799 tx/s, PostgreSQL 1,094 tx/s
- 4 luồng: DuckDB Quack
3,504 tx/s, Arrow Flight 1,224 tx/s, PostgreSQL 2,180 tx/s
- 8 luồng: DuckDB Quack
5,434 tx/s, Arrow Flight 1,358 tx/s, PostgreSQL 4,320 tx/s
- Quack vượt PostgreSQL tới mức 8 luồng song song, và cho thấy thông lượng tối đa khoảng 5.500 tx/s
- Sau mức đó, hệ thống chạm tới giới hạn hiện tại của chính DuckDB về số lần chèn đồng thời trên cùng một bảng mỗi giây
- PostgreSQL mở rộng tốt hơn trong vùng này, và nhóm DuckDB xem đây là hạng mục sẽ xem xét trong tương lai gần
- Arrow Flight hoạt động không tốt như dự đoán, chỉ đạt khoảng một nửa hiệu năng của PostgreSQL
- Script benchmark đã được công khai
Trường hợp sử dụng và ý nghĩa đối với DuckDB
- Quack cho phép sử dụng DuckDB nhiều người chơi, nơi nhiều tiến trình riêng lẻ có thể cùng sửa song song nội dung của cùng một bảng ở cục bộ hoặc từ xa
- Một số chức năng trước đây cũng có thể làm được với DuckLake, nhưng Quack giúp đơn giản hơn và cho hiệu năng cao hơn nhiều
- Phạm vi ứng dụng của DuckDB được mở rộng trong các trường hợp mà trạng thái tập trung quan trọng hơn truy vấn cục bộ siêu gần
- Sự phổ biến của data lake đã cho thấy dữ liệu không phải lúc nào cũng ở cục bộ, và Quack là tính năng phù hợp với xu hướng đó
- Quack sẽ được tích hợp vào DuckLake, cho phép chính DuckDB trở thành Catalog server có thể truy cập từ xa
- Việc tích hợp này có thể mở ra các tính năng mới như data inlining
- Câu hỏi bổ sung có trong Quack FAQ
- DuckDB đang dịch chuyển xa hơn khỏi ngách ban đầu là cơ sở dữ liệu in-process cho phân tích tương tác, để tiến gần hơn tới vai trò thành phần cốt lõi của kiến trúc dữ liệu hiện đại
Vì sao không dùng Arrow Flight SQL
- Các dự án liên quan như Arrow và ADBC có giá trị như API trao đổi giúp giảm ma sát trong việc trao đổi dữ liệu giữa các hệ thống, tương tự ODBC và JDBC
- Tuy vậy, DuckDB thận trọng với việc dùng các định dạng trao đổi như Arrow ở bên trong hệ thống
- Cấu trúc nội bộ cho kết quả trung gian của truy vấn trong DuckDB ở một số mặt gần với Arrow, nhưng ở các mặt khác thì khá khác biệt
- Nhóm phát triển cho rằng để tiếp tục đổi mới hệ thống dữ liệu, họ không nên bị ràng buộc bởi định dạng do bên ngoài kiểm soát, nên Quack dùng cơ chế tuần tự hóa riêng
- Dùng tuần tự hóa riêng cũng cho phép triển khai ngay khi cần kiểu dữ liệu mới hoặc thông điệp giao thức mới
- Arrow Flight SQL có thiết kế mà mọi truy vấn đều cần ít nhất hai lần round-trip giao thức, tức
CommandStatementQuery và DoGet
- Cách này không lý tưởng cho các tác vụ cập nhật nhỏ, đặc biệt trong môi trường có độ trễ cao hơn
- Quack được thiết kế để với truy vấn nhỏ có thể thực thi truy vấn và fetch kết quả chỉ trong một round-trip duy nhất
Kế hoạch sắp tới
- Quack sẽ được tích hợp vào DuckLake để có thể dùng server DuckDB từ xa làm DuckLake catalog
- Việc tích hợp này được kỳ vọng sẽ cải thiện hiệu năng đáng kể, đặc biệt ở inlining
- Trong vài tháng tới, nhóm phát triển sẽ tiếp tục hoàn thiện Quack và dự định phát hành bản production đầu tiên cùng DuckDB v2.0 vào mùa thu năm nay
- Họ cũng dự định cho phép tự động cài đặt và tự động nạp khi cần extension Quack
- Dùng parser mới, họ cũng dự định cải thiện cú pháp để DuckDB giao tiếp với cơ sở dữ liệu SQL từ xa
- Ở phần core của DuckDB, họ dự định tăng mạnh số giao dịch mỗi giây để có thể mở rộng giao dịch vượt xa 8 luồng song song
- Ngoài xác thực và phân quyền, họ cũng đang xem xét cho phép mở rộng giao thức Quack để extension DuckDB có thể thêm thông điệp giao thức mới và mã xử lý tương ứng
- Họ cũng đang cân nhắc bổ sung giao thức sao chép trên Quack để sao chép thay đổi của một instance DuckDB sang server khác và tạo cụm read replica
- Quack và phần giới thiệu ban đầu cũng sẽ được trình bày tại hội nghị cộng đồng DuckCon #7 vào ngày 24 tháng 6
- Ngoài ra còn có trang riêng cho dự án Quack
1 bình luận
Ý kiến trên Hacker News
Tuần trước tôi vừa ước có đúng thứ như thế này, thời điểm thật hoàn hảo
Tôi đang đẩy dữ liệu cảm biến vào DuckDB bằng một server Deno, nhưng nếu không tắt server thì không thể dùng
duckdb -uiđể xem dữ liệuTôi không muốn gắn thêm tính năng vào server chỉ để xem nội dung DB nên định tạm thời sống chung với nó, nhưng thứ này giải quyết gọn gàng đúng vấn đề đó và cả những vấn đề tương tự tôi từng gặp với DuckDB
DuckDB là công nghệ tôi thích nhất trong giai đoạn 2025/26, và nó đã ăn sâu vào nhiều workflow như làm việc với LLM, lưu trữ dữ liệu, phân tích, pipeline dữ liệu, v.v.
Tôi rất quan tâm nhưng vẫn chưa lồng DuckDB vào cách giải quyết vấn đề của mình một cách tự nhiên, nên cũng chưa rõ có thể ánh xạ nó vào những use case nào
Tuyệt. Tôi đang xem có nên dùng DuckDB cho framework ứng dụng nội bộ của công ty không, và thứ này đã giải quyết câu hỏi kiểu “thế scale ngang thế nào?”
Xin dành lời khen cho đội ngũ DuckDB, và tôi cũng thích việc giao thức được đặt tên là Quack
Tôi đang làm một dự án mã nguồn mở lưu trữ và truy vấn dữ liệu quan sát, tức metrics, logs và traces, trong Parquet, và dù rất đồng ý với việc dùng định dạng lưu trữ mở cùng catalog mở, tôi vẫn thấy khó chịu với khả năng sử dụng của Apache Iceberg
Nhìn cái này khiến DuckLake trở nên hấp dẫn hơn nhiều với use case của tôi, và tôi rất mong chờ xem nó sẽ đi đến đâu
https://github.com/smithclay/duckdb-otlp
DuckDB rất hay nhưng tôi không rõ nó đang muốn trở thành cái gì
Cách dùng mới cứ liên tục xuất hiện, và không dễ để nhìn một phát là hiểu cách nào là đúng
Nỗ lực lần này khá nhất quán, và ở một khía cạnh nào đó là đưa nó trở lại một mô hình sử dụng quen thuộc: cơ sở dữ liệu quan hệ client-server truyền thống
Vốn dĩ relational DBMS là hệ thống đồng thời nhiều người dùng, còn DuckDB là một engine cục bộ rất nhanh với nhiều use case vì có thể nhúng vào hệ thống khác
Nó giống như hỏi SQLite muốn trở thành gì. Nó có trong điện thoại, trình duyệt, ứng dụng desktop, thiết bị IoT, và mọi người đã mở rộng nó theo nhiều hướng. Khác biệt ở đây là đây không phải bên thứ ba mà là bên thứ nhất, và với tôi đây là một bước đi rất dễ hiểu
Ứng dụng theo dõi tài nguyên trên S3 và kéo về khi etag thay đổi
Có thể đạt hiệu năng kiểu BigQuery hay ClickHouse mà không cần tự vận hành hạ tầng đó hay trả chi phí cho nó
Nó không hoàn hảo cho mọi trường hợp, nhưng xử lý được nhiều thứ hơn tôi từng nghĩ
Giờ bản thân engine không còn luôn là chỗ đau nữa, mà vấn đề nằm ở phần xung quanh. DB đang chạy, đường dẫn S3, file Parquet, thông tin xác thực, thực thi lặp lại được, export, kiểm chứng, và những khoảnh khắc script dùng một lần âm thầm biến thành hạ tầng
Quack làm phần remote/server gọn gàng hơn, nhưng xu hướng lớn hơn có vẻ là DuckDB đang trở thành lớp SQL bên trong công cụ thay vì là công cụ dành trực tiếp cho người dùng cuối
Họ không giải thích “concurrent writers” là gì
Trông như họ chỉ đang tuần tự hóa ghi ở phía server thôi
Tôi không thấy lý do gì để tính năng này bỗng nhiên lại tuần tự hóa mọi thao tác ghi
Có vẻ hữu ích cho những bộ dữ liệu phân tích nội bộ nhỏ mà bạn muốn đặt trên server dùng chung của nhóm
Dùng trong homelab chắc cũng rất đáng thử
Điểm mạnh lớn của giao thức server này là có thể chia sẻ một server có nhiều RAM và tận dụng cache dùng chung cho dữ liệu gần đây
Tôi có một ứng dụng C++ và trong lúc chạy thì mọi thứ đều nằm trong bộ nhớ
Giữa các phiên, nó được lưu ra đĩa dưới dạng XML và hoạt động tốt, nhưng về bản chất chỉ dành cho một người dùng, còn một số khách hàng muốn tổng quát hóa để nhiều người có thể đọc và ghi cùng lúc
Nhu cầu hiệu năng thấp, chỉ cỡ 2~3 người cùng lúc cập nhật vài nghìn bản ghi. Với trường hợp như thế, DuckDB + Quack có phải là lựa chọn tốt không? Hay có lựa chọn nào tốt hơn? Tôi cũng đã xem SQLite nhưng hiểu rằng nó không hoạt động theo mô hình client-server
Tôi nghĩ sẽ khó tìm được lựa chọn tốt để dùng cho nhiều người dùng đồng thời mà không phải host một DB ở phía server theo cách nào đó
Tất nhiên vẫn có thể, giống như một số game tự xây client-server multiplayer riêng, nhưng thành thật mà nói, host Postgres hay SQLite thì rẻ và dễ đến mức vô lý, và trên hết đó là cách tiếp cận chuẩn cho bài toán này
Quá tuyệt. Tôi đang dùng DuckDB để làm một ứng dụng bảng tính dạng cột kiểu Excel, nhưng lại phải dựng lại “client” thông qua một tầng HTTP truyền thống
Câu hỏi “DuckDB muốn trở thành gì” cứ lặp đi lặp lại, nhưng tôi nghĩ câu trả lời đã rất rõ rồi
Nó muốn trở thành SQLite cho phân tích: có thể nhúng, không cần cấu hình, chạy ở mọi nơi
Quack chỉ là phần mở rộng chữ “mọi nơi” đó để bao gồm cả remote
Ở mục “Có thể dùng DuckDB cùng Quack làm cơ sở dữ liệu catalog cho DuckLake không?” thì họ viết “Chưa được, nhưng chúng tôi đang làm!”
Trông có vẻ là một use case ngách, nhưng lại là phần tôi quan tâm nhất
Lakehouse của chúng tôi dùng DuckLake và dùng Postgres cho catalog, nhưng catalog DuckDB / Quack có vẻ sẽ là một lựa chọn thay thế rất tuyệt
Có nhiều lý do. Thứ nhất, xử lý inline sẽ không bị lệch kiểu dữ liệu. Nếu dùng catalog không phải DuckDB thì nhiều kiểu không ánh xạ 1:1, nên khi xử lý các kiểu đó sẽ phát sinh thêm overhead
Thứ hai, bạn có thể giữ nguyên hiệu năng phân tích của DuckDB trên catalog, và giờ cả hiệu năng giao dịch nữa. DuckDB đọc DuckDB đơn giản là nhanh hơn scanner Postgres/SQLite của chúng tôi
Thứ ba, không có round-trip cho retry. Có thể dễ dàng(tm) chạy toàn bộ logic retry ở phía DuckDB server. Hiện tại những lần retry như vậy tạo ra nhiều round-trip đến Postgres, gây thành nút thắt hiệu năng khi workload có mức tranh chấp cao
Tiện nói luôn, tôi là dev của duckdb/ducklake
Có lẽ chỉ vài ngày nữa là có thể thử được