Ohhnews

分类导航

$ cd ..
foojay原文

搭建 DuckDB Quack 服务器:Hello World 入门指南

#duckdb#quack协议#客户端服务器#数据库#远程查询

DuckDB 以进程内数据库而闻名,堪称分析领域的 SQLite:不需要服务器,不需要守护进程,只是应用内部的一个库,只需在 POM 中加一个依赖。DuckDB 2.0 在此基础上增加了客户端-服务器模式,即 Quack 远程协议,它允许一个 DuckDB 实例通过网络向另一个 DuckDB 实例提供查询服务。

服务器和客户端都只是 DuckDB。没有单独的守护进程需要安装,也没有新的查询语言需要学习。你用一个 SQL 函数启动服务器,再用 ATTACH 连接它——这正是你已经在用来连接 Parquet 文件和 Postgres 数据库的同一条语句。

为什么要把 DuckDB 作为服务器运行?

把 DuckDB 作为服务器运行仍然和嵌入式版本一样简单,但它允许多个进程访问同一份数据。查询在数据所在的位置执行,因此客户端只收到结果,而不是整个数据集。

以下是几种常见的使用场景,既包括本地也包括远程:

  • 同一台机器上的多个进程共享同一个 DuckDB。DuckDB 文件是单写入者的,所以通常只有一个进程能以读写方式打开它。运行本地服务器消除了这一限制,因此 Web 应用的各个工作进程、仪表盘和 notebook 可以同时查询同一份数据。
  • 一个团队可以让各自的 DuckDB 实例指向同一台服务器,而不必每个人都保留一份数 GB 的文件副本。
  • 查询远程机器上的数据集,而无需先下载它。
  • 把共享的 DuckDB 放在 Java 服务后面,因为 JDBC 连接可以像另一个 DuckDB CLI 一样轻松地充当客户端。

本文是一个小型的端到端示例:两个终端、一行数据、一个 world。本文所有内容都使用官方的 quack 核心扩展。公告文章介绍了其背后的设计。

第 1 步:安装 DuckDB 2.0

官方安装程序覆盖所有平台。在 macOS 和 Linux 上,运行 shell 脚本:

$ bash
curl https://install.duckdb.org | sh

在 Windows 上,改用 PowerShell 安装程序:

$ powershell
powershell -NoExit -ExecutionPolicy Bypass -Command "irm https://install.duckdb.org/install.ps1 | iex"

无论采用哪种方式,安装完成后都检查版本:

$ bash
duckdb --version

你需要 v2.0.0 或更高版本。该版本发布了更快、更稳定的 Quack 协议实现。

quack 扩展会在首次使用时自动安装并自动加载,因此无需再下载其他内容。

第 2 步:启动服务器(终端 A)

打开一个终端,启动一个存放在文件中的 DuckDB 数据库,这样数据在会话结束后仍会保留:

$ bash
duckdb hello.duckdb

然后,在 DuckDB 提示符下启动服务器,并创建一些可供查询的数据:

$ query
CALL quack_serve('quack:localhost', token = 'super_secret');

CREATE TABLE hello AS FROM VALUES ('world') v(s);

quack_serve 开始在 quack: 协议方案上监听。quack:localhost 是 quack:localhost:9494 的简写,因为 9494 是 Quack 的默认端口。token 是客户端必须提供的共享密钥。

如果省略 token,Quack 会为你生成一个随机令牌,并在结果的 auth_token 列中返回。复制该值,并在下一步交给客户端。

保持此终端打开。关闭它就会停止服务器。

第 3 步:以客户端身份连接(终端 B)

打开第二个终端,启动一个全新的 DuckDB。这个实例不需要文件:

$ bash
duckdb

首先把令牌存储为 secret,并将其作用域限定为你要连接的服务器,这样就不必在每条语句中重复它:

$ query
CREATE SECRET (
    TYPE quack,
    TOKEN 'super_secret',
    SCOPE 'quack:localhost'
);

现在附加远程服务器并从它读取:

$ query
ATTACH 'quack:localhost' AS remote;

FROM remote.hello;

你应该会看到一行,内容为 world。这就是你的 hello world:查询在终端 A 的服务器上运行,结果返回到终端 B 的客户端。

第 4 步:用 CONNECT 让整个会话走服务器

可以避免给每张表都加上 remote. 前缀。CONNECT 会把整个会话指向服务器,因此未加限定的名称会在那里解析:

$ query
CONNECT remote;

FROM hello;
SELECT 42;

DISCONNECT;

连接期间,你的 SQL 在服务器上运行,结果会流式返回。DISCONNECT 会让会话返回本地数据库。

第 5 步:不通过 ATTACH 运行单条查询

对于单条查询,quack_query 完全跳过 ATTACH 步骤:

$ query
FROM quack_query(
    'quack:localhost',
    'SELECT ''hello world''',
    token = 'super_secret');

查询在远程执行,服务器抛出的任何内容(例如解析错误或表不存在)都会显示在你的客户端中。

第 6 步:停止服务器(终端 A)

回到终端 A,关闭服务器:

$ query
CALL quack_stop('quack:localhost');

走出 localhost

当客户端和服务器位于不同机器上时,有几处会发生变化:

  • 默认情况下,服务器除本地主机名外拒绝绑定到任何地址。要监听外部地址,请传入 allow_other_hostname:

    $ query
    CALL quack_serve('quack:0.0.0.0:9494', allow_other_hostname = true);
    

    非本地 Quack URI 默认使用 HTTPS,并采用自签名证书。在生产环境中,请在 Quack 前面放置一个终止 TLS 的反向代理,或者设置 ssl_cert_file 和 ssl_key_file 来使用你自己的证书。

  • 因为客户端本身就是一个 DuckDB,所以任何 DuckDB 连接都可以作为客户端,包括 JDBC 或 Python 连接。Java 和 Python 代码会运行上面所示的相同 CREATE SECRET 和 ATTACH 语句,因此 Java 应用可以位于共享 DuckDB 之前。

这就是完整的闭环:安装、作为服务运行、连接、查询、停止。hello 表可以变成真实的表、Parquet 文件或 DuckDB 能读取的任何其他内容,而客户端不需要知道这些东西位于哪里。## 参与讨论

数据库 [LOADING...]
[LOADING...]Geertjan Wielenga2026年10月27日 290 次浏览

DuckDB 2.0 现已发布

数据库Java

数据库 [LOADING...]
[LOADING...]Geertjan Wielenga2026年8月6日 816 次浏览

在 Maven 应用中嵌入 DuckDB(并将其用于非数据库场景)

数据库DuckDBJava

开发者工具 [LOADING...]
[LOADING...]Geertjan Wielenga2026年8月29日 529 次浏览

在 GraalVM 原生镜像中运行 DuckDB 的 JDBC 驱动

开发者工具DuckDBJava

开发者工具 [LOADING...]
[LOADING...]Geertjan Wielenga2026年9月8日 654 次浏览

从 OpenTelemetry 到 DuckDB

开发者工具DuckDBOpenTelemetry