- QuackはDuckDBインスタンス間の通信を提供し、クライアント・サーバー構成と、複数の同時書き込み者による同じデータベースの利用を可能にする
- DuckDBはインプロセスアーキテクチャを維持しつつ、複数プロセスが同じファイルを変更する際に必要な状態同期をリモートプロトコルで処理する
- QuackはHTTPベースのリクエスト・レスポンスプロトコルで、
application/duckdbシリアライズとトークン認証を使い、デフォルトポートは9494
- ベンチマークでは、Quackは6,000万行を4.94秒で転送し、小さなappendテストでも8スレッド基準で約5,434 tx/sを記録した
- QuackはDuckLake統合、リモートCatalogサーバー、自動インストール・ロード、プロトコル拡張、レプリケーションプロトコルを計画しており、DuckDB v2.0の時期での本番リリースを目指している
Quackの目的と背景
- QuackはDuckDBインスタンス同士を通信させるリモートプロトコルで、DuckDBをクライアント・サーバー構成で動作させ、複数の同時書き込み者が同じデータベースを使えるようにする
- DuckDBは2019年からインプロセスアーキテクチャを強調しており、別個のサーバーやプロトコルなしに低レベルAPI呼び出しで動作する方式は、Pythonノートブックのような対話型データサイエンス作業や、アプリケーション内でSQL機能を提供する用途に適していた
- 同じDuckDBデータベースファイルを複数プロセスが同時に変更するには、DuckDBがメインメモリ上に保持している多くの状態をプロセス間で同期する必要がある
- 従来は、別個のRPCプロセス、Arrow Flight SQL protocolを使うプロジェクト、MotherDuckの独自プロトコル、PostgreSQLとpg_duckdbを組み合わせた「EleDucken」のような回避策があった
- DuckDBを汎用データ加工ツールへ拡張するには、インプロセス機能に加えてクライアント・サーバープロトコルが新たなユースケースを開く可能性がある
Quackの使い方
- Quackでは、2つ以上のDuckDBインスタンスが相互に通信し、DuckDBがクライアントとサーバーの両方の役割を担う
- 2つのインスタンスは、別々のコンピューター、リモート環境、または同じノートPC上の別々のターミナルウィンドウに存在しうる
- Quack拡張は現在
core_nightlyリポジトリにあり、現行リリース版のDuckDB v1.5.2で利用できる
- サーバー側のDuckDBインスタンスでは、Quackをインストール・ロードした後に
quack_serveを呼び出し、例ではquack:localhostと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);
- クライアント側のDuckDBインスタンスでもQuackをインストール・ロードし、
CREATE SECRETでトークンを設定した後、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;
- この構成により、DuckDB #2からリモートテーブル
helloの値worldを参照できる
- ローカルインスタンスからリモートインスタンスへデータをコピーすることもでき、例ではDuckDB #2で
remote.hello2テーブルを作成し、DuckDB #1でFROM hello2;として確認する
- 複雑なクエリや大規模データセットでは、クエリをそのままリモート側へ送る**
query関数**により、どの処理がリモートで実行されるかをより細かく制御できる
FROM remote.query(
'SELECT s FROM hello'
);
プロトコル設計
-
HTTPベース
- QuackはHTTPの上に直接構築されており、HTTPはTCPとその下位層の上で事実上の標準プロトコル層として定着している
- HTTPスタックはメッセージストリーム転送向けに効率よく最適化されており、適切に実装すればオーバーヘッドは小さい
- ロードバランシング、認証、ファイアウォール、侵入検知といった分野でHTTPの扱い方は広く知られている
- HTTPを使うため、DuckDB-Wasm配布版もQuackをネイティブに利用できる
- ブラウザーで動くDuckDBが、Quackを通じてEC2サーバー上で動作するDuckDBインスタンスへ直接接続できる
-
リクエスト・レスポンスパターン
- Quackのやり取りは常にクライアント主導のリクエスト・レスポンスパターンで動作する
- メッセージには、トークン認証のための接続リクエスト、クエリ実行リクエスト、レスポンスの最初の部分の返却、大きな結果を取得するための後続fetchメッセージなどが含まれる
- 大規模な結果は複数スレッドで並列取得できる
-
シリアライズ
- リクエストとレスポンスは、新しいMIMEタイプ**
application/duckdb**でエンコードされる
- このエンコーディングは、データ型や結果セットのような複雑な構造のためにDuckDB内部のシリアライズプリミティブを活用する
- 同じプリミティブは長年にわたりDuckDBのWALファイルでも使われており、かなり最適化・検証されている
-
暗号化と公開方法
- Quackはサーバー起動時にデフォルトでランダムな認証トークンを生成し、クライアントはこのトークンを提示する必要がある
- Quackサーバーはデフォルトで
localhostのみにバインドされ、この挙動は上書き可能
- デフォルトではSSLを使用せず、
localhost通信のためだけにそのインフラや依存関係を追加するのは適切でないと考えている
- DuckDB Quackエンドポイントをインターネットへ直接公開することは推奨されない
- QuackをWebに公開する必要がある場合は、nginxのような一般的なHTTPエンドポイントを使い、そのプロキシでLet’s EncryptなどによりSSLを終端することを強く推奨している
- Quackクライアントは、ローカル以外の接続についてはSSLが有効だと想定しており、この挙動は上書き可能
- 関連設定はリバースプロキシのドキュメントにある
-
ラウンドトリップ回数の最適化
- Quackは、クエリに必要なプロトコルのラウンドトリップ回数を減らすよう設計されている
- 接続後は、1つのクエリを単一ラウンドトリップで処理でき、レイテンシに敏感な環境で有利
- 大きなレスポンス転送も最適化されており、DuckDBチームはQuackが現在ソケット経由でテーブルを転送する最速の方法だと見ている
- 数百万行を数秒以内で転送できるというベンチマーク結果を示している
-
認証と認可
- QuackはDuckDBの拡張性の哲学に合わせて、認証と認可のモデルを設計している
- デフォルトの認証方式と制限のないデフォルト認可を提供するが、どちらもユーザー提供コードに置き換えられる
- サーバー起動時にランダムな認証トークンを生成し、クライアントは接続時に認証文字列を提供する
- サーバーは認証コールバックを呼び出し、デフォルトのコールバックはクライアントが提示したトークンとサーバーが生成したトークンを比較する
- 認証コールバックは設定で差し替え可能で、LDAPディレクトリ照会、テキストファイルの読み取り、任意のロジックなどを利用できる
- 認可関数も差し替え可能で、デフォルト関数はすべてのリクエストを許可する
- ユーザー定義の認可関数は、クライアントが実行しようとする各クエリを検査し、以前に使われた認証文字列と関連付けて判断できる
- このようなコールバックは通常のSQLマクロとして書くこともできる
-
デフォルトポート
ベンチマーク
- ベンチマークはUbuntu on Armを動かすAWS仮想マシンで実施された
- インスタンスタイプはm8g.2xlargeで、8 vCPU、32GB RAM、最大15Gbpsのネットワーク帯域を備える
- クライアントとサーバーが同じデータセンター内の別マシンにある実際のシナリオを再現している
- 2つのインスタンスは同じアベイラビリティゾーンに配置され、平均ping時間は約0.280msだった
-
大量転送
- 最初のベンチマークは、データベースプロトコルを通じて多くの行を転送する大量転送作業を測定する
- 比較対象はQuack、PostgreSQLプロトコル、Arrow Flight SQLプロトコル
- Arrow Flightは内部的にDuckDBを使うGizmoSQLサーバーとして提供される
- TPC-Hの
lineitemテーブルで行数を増やしながら転送し、最大6,000万行まで測定した
- 6,000万行はCSV形式で76GBに相当する
- 各結果は5回実行した際の中央値の実時間で報告される
- 主な結果は以下のとおり
- 100k行: DuckDB Quack
0.07 s, Arrow Flight 0.07 s, PostgreSQL 0.20 s
- 1M行: DuckDB Quack
0.24 s, Arrow Flight 0.38 s, PostgreSQL 2.20 s
- 10M行: DuckDB Quack
0.89 s, Arrow Flight 2.90 s, PostgreSQL 25.64 s
- 60M行: DuckDB Quack
4.94 s, Arrow Flight 17.40 s, PostgreSQL 158.37 s
- Quackは6,000万行を5秒未満で転送し、大規模結果セット転送で高い性能を示した
- 目的特化型のArrow Flight SQLもこの結果ではQuackに及ばず、PostgreSQLの行ベースプロトコルは全体的に不利だった
- 標準PostgreSQLクライアントは複数スレッドでの読み取りを並列化しないが、QuackとArrowは並列化できる
- DuckDBのPostgreSQL clientも一部のケースでは並列読み取りが可能
-
小さな書き込み
- 2つ目のベンチマークは小さなappend作業を測定する
- 観測可能性データを中央のDuckDBインスタンスへ集約する構成のように、小さな書き込みを中央集約する状況に相当する
- 単一トランザクションの完了に複数回のクライアント・サーバー間ラウンドトリップが必要なプロトコルには不利なテスト
- TPC-Hの
lineitemと同じ構造の空テーブルを作り、ランダム値を1行ずつ、それぞれ独立したINSERTトランザクションとして挿入した
- 並列スレッド数を増やしながら5秒間実行し、実験を5回繰り返して中央値の1秒あたりトランザクション数を報告した
- 主な結果は以下のとおり
- 1スレッド: DuckDB Quack
1,038 tx/s, Arrow Flight 469 tx/s, PostgreSQL 839 tx/s
- 2スレッド: DuckDB Quack
1,956 tx/s, Arrow Flight 799 tx/s, PostgreSQL 1,094 tx/s
- 4スレッド: DuckDB Quack
3,504 tx/s, Arrow Flight 1,224 tx/s, PostgreSQL 2,180 tx/s
- 8スレッド: DuckDB Quack
5,434 tx/s, Arrow Flight 1,358 tx/s, PostgreSQL 4,320 tx/s
- Quackは8並列スレッドまでPostgreSQLを上回り、最大約5,500 tx/sのトランザクション処理率を示した
- それ以上では、同じテーブルへの同時挿入における1秒あたり回数でDuckDB自体の現在の限界に達する
- PostgreSQLはこの領域でよりよくスケールし、DuckDBチームは近い将来の検討対象として見ている
- Arrow Flightは予想どおり良くなく、PostgreSQLのおおよそ半分程度の性能だった
- ベンチマークスクリプトが公開されている
ユースケースとDuckDBにおける意味
- Quackは、複数の個別プロセスがローカルまたはリモートから同じテーブル内容を並列に変更できるマルチプレイヤーDuckDB利用を可能にする
- 一部の機能はDuckLakeでも可能だったが、Quackはそれをよりシンプルにし、はるかに高い性能を提供する
- 中央状態が超近接のローカルクエリより重要なユースケースで、DuckDBを活用できる範囲が広がる
- データレイクの普及により、データが常にローカルにあるとは限らないことはすでに明らかであり、Quackはこうした方向性に合致する機能となる
- QuackはDuckLakeに統合される予定で、DuckDB自体がリモートアクセス可能なCatalogサーバーになれるようにする
- この統合により、データインライン化のような新機能が開かれる可能性がある
- 追加の質問はQuack FAQにある
- DuckDBは、対話型分析向けインプロセスデータベースという初期のニッチから離れ、現代データアーキテクチャの中核コンポーネントへとさらに移行しつつある
Arrow Flight SQLを使わなかった理由
- ArrowやADBCのような関連プロジェクトは、ODBCやJDBCのようにシステム間データ交換の摩擦を減らす交換APIとして価値がある
- ただしDuckDB内部でArrowのような交換形式を使うことには慎重
- DuckDBのクエリ中間結果の内部構造は、ある面ではArrowに近いが、別の面ではかなり異なる
- データシステムの革新を続けるには、外部で制御される形式に縛られるべきではないと考え、Quackでは独自シリアライズを使っている
- 独自シリアライズを使えば、新しいデータ型やプロトコルメッセージが必要になったときすぐに展開できる
- Arrow Flight SQLには、すべてのクエリで最低2回のプロトコルラウンドトリップ、つまり**
CommandStatementQueryとDoGet**を必要とする設計がある
- この方式は、小さな更新作業、特にレイテンシが大きい環境では理想的でない
- Quackは小さなクエリに対して、単一ラウンドトリップでクエリ実行と結果fetchを可能にするよう設計されている
今後の計画
- QuackはDuckLakeに統合され、リモートDuckDBサーバーをDuckLake catalogとして使えるようになる予定
- この統合は、特にインライン化で性能を大きく改善すると期待されている
- 今後数か月でQuackを磨き込み、今年秋に予定されているDuckDB v2.0とともに最初の本番リリースを行う計画
- Quack拡張が必要なときに自動インストールと自動ロードができるようにする計画がある
- 新しいparserを用いて、DuckDBでリモートSQLデータベースと対話する構文も改善する計画
- DuckDBコアの観点では、1秒あたりトランザクション数を大きく増やし、8並列スレッドを大きく超えてトランザクションをスケールできるようにする計画
- 認証と認可を超えて、DuckDB拡張が新しいプロトコルメッセージや処理コードを追加できるようQuackプロトコル拡張を許可する方法も検討中
- Quackの上にレプリケーションプロトコルを追加し、DuckDBインスタンスの変更を他サーバーへ複製して、読み取りレプリカクラスタを構成する案も検討中
- Quackと初期導入の内容は、6月24日のコミュニティカンファレンスDuckCon #7でも扱われる予定
- 別途Quack projectページも提供されている
1件のコメント
Hacker Newsのコメント
先週まさにこういうものが欲しいと思っていたので、タイミングが絶妙
Denoサーバーでセンサー値をDuckDBに流し込んでいたが、サーバーを止めないと
duckdb -uiでデータを確認できなかったDBの内容を見るためにサーバーへ機能を追加したくはなかったので、しばらくはそのままやり過ごすつもりだったが、これはその問題と DuckDB で感じていた似たような問題をきれいに解決してくれる
DuckDB は 2025/26 年でいちばん気に入っている技術で、LLM 作業、データ保存、分析、データパイプラインなど、さまざまなワークフローに深く入り込んでいる
興味はとてもあるけれど、まだ問題解決のやり方に DuckDB を自然に組み込めておらず、どんなユースケースに対応づけられるのかもあまり見えていない
すばらしい。社内アプリのフレームワークで DuckDB を使えないか見ていたが、これで「では水平スケーリングはどうするのか」という問題が解決した
DuckDB チームに拍手を送りたいし、プロトコル名が Quack なのも気に入っている
観測可能性データ、つまりメトリクス・ログ・トレースを Parquet に保存して問い合わせるオープンソースプロジェクトをやっていて、オープンなストレージフォーマットとカタログを使いたいという点には強く同意するが、Apache Iceberg の使い勝手にはもどかしさがあった
これを見て、DuckLake が自分のユースケースではずっと面白く感じられるようになったし、今後どこへ向かうのか楽しみだ
https://github.com/smithclay/duckdb-otlp
DuckDB は良いが、何になろうとしているのかはよく分からない
使い方が次々に増えていて、どれが自分に合うやり方なのか一目で把握しにくい
今回の試みはかなり一貫していて、従来のクライアントサーバー型リレーショナルデータベースという馴染みのある利用モデルへ戻している面がある
リレーショナル DBMS はもともと多ユーザー同時実行システムであり、DuckDB はほかのシステムに埋め込める、さまざまなユースケースを持つ非常に高速なローカルエンジンだ
SQLite に何になりたいのかと尋ねるのに似ている。スマートフォン、ブラウザー、デスクトップアプリ、IoT デバイスに入っていて、人々がいろいろな方向へ拡張してきた。違いは、ここではサードパーティーではなくファーストパーティーだという点で、自分にはとても理解しやすい動きに見える
アプリは S3 上のアセットを監視し、etag が変わったら取得する
BigQuery や ClickHouse のような性能を、そのインフラを自前で運用したり費用を払ったりせずに得やすい
あらゆるケースで完璧ではないが、予想以上に多くのことをこなせる
いまやエンジン自体が常に痛点というわけではなく、問題は周辺部にある。ライブ DB、S3 パス、Parquet ファイル、認証情報、再現可能な実行、エクスポート、検証、そして単発スクリプトが静かにインフラになる瞬間だ
Quack はリモート/サーバー部分をよりきれいにするが、より大きな流れとしては、DuckDB はエンドユーザー向けツールというより、ツール内部の SQL レイヤーになっていくように見える
「同時ライター」が何なのか説明されていない
見たところ、単に サーバー側で書き込みを直列化 しているように見える
この機能によって突然すべての書き込みを直列化する理由は見当たらない
共有チームサーバーに置いておきたい小規模な社内分析データセットには便利そう
ホームラボ用途でも十分検討に値する
このサーバープロトコルの大きな利点は、大容量メモリを積んだサーバーを共有し、最近のデータに対する共有キャッシュを活用できることだ
C++ アプリケーションがあり、実行中はすべてがメモリ上にある
セッション間では XML としてディスクに保存していて、うまく動いてはいるが、厳密には単一ユーザー向けで、何人かの顧客は複数ユーザーが同時に読み書きできるよう一般化してほしいと言っている
性能要件は低く、同時に 2〜3 人が数千件程度を更新するレベルだ。こういう場合、DuckDB + Quack は良い選択肢だろうか? それとももっと良い選択があるだろうか? SQLite も見たが、クライアントサーバーとしては動作しないと理解している
同時ユーザーを扱う DB を、何らかの形でサーバー側にホスティングせずに使える良い選択肢を見つけるのは難しいと思う
もちろん、一部のゲームがマルチプレイヤー向けのクライアントサーバーを自前で作るように不可能ではないが、正直なところ Postgres や SQLite をホスティングするのはばかばかしいほど安くて簡単で、何よりこの問題に対する標準的なアプローチだ
すばらしい。DuckDB を使って Excel のような列指向スプレッドシートアプリ を作っていたが、従来の HTTP レイヤーで「クライアント」を作り直さなければならなかった
「DuckDB が何になりたがっているのか」という問いは何度も出てくるが、答えはもう明らかだと思う
分析向けの SQLite になりたいのだ。埋め込み可能で、設定不要で、どこでも動く
Quack は、その「どこでも」にリモートを含める部分にすぎない
「Quack と一緒に DuckDB を DuckLake のカタログデータベースとして使えますか?」という問いに対して「まだですが、作業中です!」とある
ニッチなユースケースに見えるが、自分がいちばん関心を持っている部分だ
うちのレイクハウスは DuckLake を使い、カタログは Postgres を使っているが、DuckDB / Quack カタログ はすばらしい代替になりそうだ
理由はいくつかある。第一に、インライン処理で型不一致がない。DuckDB 以外のカタログを使うと、多くの型が 1:1 に対応せず、そのデータ型を扱う際に追加のオーバーヘッドが発生する
第二に、カタログ上でも DuckDB の分析性能と、今ではトランザクション性能までそのまま得られる。DuckDB が DuckDB を読むほうが、我々の Postgres/SQLite スキャナーより単純に速い
第三に、リトライのための往復がない。リトライのロジック全体を DuckDB サーバー側で簡単(tm)に実行できる。今はこの種のリトライが Postgres への複数回の往復を発生させ、競合の大きいワークロードで性能のボトルネックになっている
参考までに、duckdb/ducklake の開発者だ
数日以内に試せるようになるはずだ