Bỏ qua tới nội dung chính
Quay lại tin tức

Chạy đồng thời các truy vấn SQL trên ba máy chủ DuckDB từ xa bằng Quack

Towards Data Science· Thomas Reid· 16/8/2026general

Một thử nghiệm nhỏ trong việc thực thi SQL từ xa Bài viết Chạy SQL đồng thời trên ba máy chủ DuckDB từ xa với Quack xuất hiện đầu tiên trên Towards Data Science.

Kỹ thuật dữ liệu Chạy SQL đồng thời trên ba máy chủ DuckDB từ xa với Quack Một thử nghiệm nhỏ về việc thực thi SQL từ xa Thomas Reid Ngày 16/8/2026 16 phút đọc Ảnh minh họa bởi AI Vài tháng trước, đội ngũ phát triển DuckDB đã phát hành một giao thức truyền thông cơ sở dữ liệu có tên Quack. Mục tiêu chính của giao thức này là cho phép các cơ sở dữ liệu DuckDB đặt trên các máy chủ khác nhau giao tiếp với nhau qua HTTP theo mô hình client/server, đồng thời cho phép chúng đọc và ghi dữ liệu của nhau. Nói cách khác, sử dụng giao thức Quack, DuckDB trên máy chủ A giờ đây có thể truy vấn hoặc ghi vào cơ sở dữ liệu DuckDB trên máy chủ B từ xa. Điều này nghe có vẻ giống như xử lý dữ liệu phân tán, nhưng thực tế không phải vậy và nhóm DuckDB đã nhấn mạnh rằng Quack không hỗ trợ xử lý truy vấn phân tán. Mặc dù vậy, tôi vẫn cảm thấy hứng thú và nhận thấy nhiều ứng dụng tiềm năng cho Quack. Đặc biệt, tôi muốn tìm hiểu xem liệu có thể gửi các câu lệnh SQL song song trên mỗi máy chủ và thu thập kết quả của từng truy vấn, sau đó cung cấp chúng để sử dụng hoặc hiển thị trên một máy chủ điều phối hay không. Lưu ý rằng đây là một đề xuất khác so với việc chỉ đơn thuần kết nối các bảng giữa các máy chủ khác nhau trong một câu lệnh SQL duy nhất. DuckDB có thể thực hiện điều đó bằng cách gắn một cơ sở dữ liệu từ máy chủ B vào máy chủ A, chẳng hạn, sau đó chạy SQL trên máy chủ A có thể đọc dữ liệu trên máy chủ B như thể dữ liệu đó là cục bộ. Vì vậy, để điều tra khả năng đọc và ghi đồng thời mà Quack có thể mang lại, tôi đã tạo một kho lưu trữ GitHub có tên cluster-duck, và không, đây không phải là một cụm DuckDB phân tán. Đó chỉ là một cách chơi chữ hài hước dựa trên thành ngữ thô tục phổ biến mà bạn có thể đã biết. Nhưng nó sẽ cho phép bạn thực hiện đọc và ghi đồng thời trên các cơ sở dữ liệu DuckDB từ xa. Lưu ý: Trước khi tiếp tục, tôi muốn tuyên bố rằng tôi không có bất kỳ liên kết hoặc mối quan hệ thương mại nào với bất kỳ sản phẩm, hệ thống hoặc nhà sáng tạo nào được đề cập trong bài viết này. Thiết lập Để thử nghiệm Quack, tôi đã thiết lập 3 máy chủ AWS EC2 thông qua một CloudFormation stack. Mỗi máy chủ chứa một cơ sở dữ liệu DuckDB, trong đó một trong các máy chủ cũng đóng vai trò là nút điều phối. Bạn có thể tìm thấy CF stack trên kho lưu trữ GitHub của tôi. Từ AWS CloudShell (hoặc cục bộ nếu bạn đã cài đặt AWS CLI), sau khi đã kiểm tra kho lưu trữ, hãy triển khai stack bằng lệnh: aws cloudformation deploy \ --region us-east-2 \ --stack-name cluster-duck-test-v2 \ --template-file python-reference/infra/aws/cluster-duck-3-node.yaml \ --capabilities CAPABILITY_NAMED_IAM Đối với cả ba máy chủ EC2, các thành phần sau đã được cài đặt: Amazon Linux 2023 ARM64. Một tệp hoán đổi (swap file) 512 MB. Python 3.12 và pip. Một môi trường ảo Python tại: /opt/cluster-duck-venv duckdb==1.5.5 boto3 CLI DuckDB 1.5.5 ARM64 tại: /usr/local/bin/duckdb Tiện ích mở rộng Quack chính thức của DuckDB, được tải bởi tiến trình worker. Chương trình máy chủ Quack tại: /opt/cluster-duck/quack_server.py Cơ sở dữ liệu worker tại: /var/lib/cluster-duck/worker.duckdb Một dịch vụ systemd có tên: cluster-duck-quack.service Một bộ hẹn giờ tự động tắt, mặc định là bốn giờ. Quack lắng nghe trên cổng 9494 theo mặc định. Mã thông báo xác thực của nó được truy xuất từ một tham số được mã hóa trong SSM Parameter Store. Mã nguồn Python được sao chép lên cả ba máy chủ vì chúng chia sẻ cùng một mẫu khởi chạy CloudFormation. Tuy nhiên, bộ điều phối chỉ được cấp quyền thực thi dưới dạng lệnh trên một máy chủ – thường là worker 1. Các tệp này được cài đặt trên mọi máy chủ: /opt/cluster-duck/quack_server.py /opt/cluster-duck/seed_related_data.py /opt/cluster-duck/related_cluster_sql.py /opt/cluster-duck/cluster_duck/sql_api.py Máy chủ điều phối (Worker 1) nhận thêm các trình khởi chạy lệnh sau: /usr/local/bin/cluster-duck /usr/local/bin/cluster-duck-sql Khi chạy cluster-duck-sql trên máy điều phối, quá trình này cuối cùng sẽ khởi động: /opt/cluster-duck-venv/bin/python /opt/cluster-duck/related_cluster_sql.py Mã nguồn Python được nén và nhúng trực tiếp vào mẫu CloudFormation dưới dạng một kho lưu trữ được mã hóa Base64. Trong quá trình khởi động EC2, tập lệnh user-data sẽ: Giải mã kho lưu trữ đã nhúng. Tạo thư mục /opt/cluster-duck. Giải nén các tệp Python vào thư mục đó. Tạo các trình khởi chạy lệnh trên worker 1. Khởi động dịch vụ Quack trên mọi worker. Mọi thứ cần thiết đều được chứa trong tệp CloudFormation. Cách thức điều phối hoạt động Quack chuyển từng câu lệnh SQL đến máy chủ DuckDB được chọn và trả về kết quả. Phần điều phối ba lệnh gọi là mã Python chạy trên Worker 1. Đầu tiên, mọi đối số —query hoặc —query-file được xác thực là một câu lệnh SQL duy nhất và được chuyển thành QueryFragment. Các fragment được gắn nhãn theo thứ tự chúng được cung cấp: fragments.append( QueryFragment(worker_id, f"query-{index}", sql) ) Máy điều phối sau đó tạo một luồng (thread) cho mỗi fragment và một rào chắn (barrier) với cùng số lượng người tham gia: barrier = threading.Barrier(len(fragments)) epoch = time.perf_counter() def run_fragment(fragment): barrier.wait() started = time.perf_counter() raw_result = self.executor(fragment.worker_id, fragment.sql) finished = time.perf_counter() return { "start_offset_ms": (started - epoch) * 1000, "duration_ms": (finished - started) * 1000, "result": raw_result, } with ThreadPoolExecutor(max_workers=len(fragments)) as pool: futures = { pool.submit(run_fragment, fragment): fragment for fragment in fragments } Rào chắn giữ các luồng cho đến khi mọi fragment sẵn sàng, sau đó giải phóng chúng cùng lúc. Chúng sẽ không bắt đầu chính xác cùng một chu kỳ CPU vì việc lập lịch hệ điều hành thông thường vẫn được áp dụng, đó là lý do tại sao đầu ra bao gồm một độ lệch bắt đầu được đo lường. Mỗi fragment có kết nối máy khách DuckDB cục bộ riêng trên máy điều phối. Kết nối đó tải Quack, gắn một worker từ xa và gửi câu lệnh thông qua remote.query(): with duckdb.connect() as connection: connection.execute("INSTALL quack") connection.execute("LOAD quack") connection.execute(

Nguồn tin: Towards Data Science — Tác giả: Thomas Reid. Bản dịch tiếng Việt do AI thực hiện, có thể có sai sót.