
2026/05/13 2:54
# Quack: DuckDB クライアント−サーバープロトコル ## 概要 DuckDB は分散データベースアーキテクチャを採用しており、クライアント−サーバー間での通信のためにプロトコルの定義と実装が不可欠です。本ドキュメントでは、そのための通信プロトコル「Quack」について解説いたします。 ### プロトコルの設計目標 * **高スケーラビリティ**: 多数のクライアントから同時にクエリを受付けることを可能にします。 * **低遅延**: クライアントとサーバー間の通信を最小限とし、高速なレスポンスを実現します。 * **互換性**: 他のデータベースシステムとの接続方法を柔軟に対応できます。 ### 機能一覧 - プロトコル仕様の定義 - セキュリティ認証機構の導入 - データ転送用の圧縮アルゴリズムの実装 - エラーハンドリングメカニズムの整備
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
DuckDB は複数の並行書き込みがプロセス間でのデータベース状態を安全に共有できるようになるクライアント - サーバーシステムである「Quack」プロトコルを導入しました。HTTP を基盤とし、
application/duckdb MIME タイプを使用した Quack は、バッチ処理操作と単一ラウンドトリップクエリ実行による小規模トランザクションの両方をサポートします。セキュリティ上のデフォルト設定には、起動時に自動生成されるトークン、localhost へのバインドのみ(上書き可能)、リモート接続用の自動 SSL が含まれており、認証は LDAP、テキストファイル、または SQL マクロなどのコールバックを介してカスタマイズでき、デフォルトの権限付与ではすべてのリクエストを許可しますが、これを変更することもできます。
現在、
core_nightly リポジトリの拡張機能としてバージョン 1.5.2 から利用可能です。Quack を使用するには、quack 拡張機能をインストールして読み込み、quack_serve でサーバーを開始し、ATTACH を介してリモートエンドポイントを接続する必要があります。AWS m8g.2xlarge インスタンスでのベンチマークでは、Quack はバッチデータ転送において PostgreSQL および標準の Arrow Flight サービスを上回る性能を発揮し、小規模書き込みの場合 8 スレッドで最大約 5,434 トランザクション/秒、6,000 万行未満の転送時間を記録しました。また、混合ワークロードに対して柔軟なスループットを提供します。
設計は、Arrow Flight SQL などの外部交換形式への依存を避けることを明確にし、ラウンドトリップ数を最小化するとともに形式制限を回避することを目的としています。Quack は、秋に DuckDB v2.0 とともに本番リリースされ、インストール/ロードの簡素化、リモート SQL シNTAX の改良、コアエンジンアップグレードによる TPS 向上を特徴とします。これらは次期 DuckLake プロジェクトのための高パフォーマンスなリモートカタログサーバーとして機能し、要求の高いデータ操作に対して単一ラウンドトリップ実行の高速化およびスループット向上をもたらします。将来の計画には、拡張機能が新しいプロトコルメッセージを定義することを許可すること、および読み取りレプリカクラスター向けのレプリケーションプロトコルの追加が含まれます。
本文
TL;DR: DuckDB インスタンス同士が「Quack(クアック)」というリモートプロトコルを使用して通信できるようになりました。これにより、複数の同時書き込みに対応したクライアント・サーバー構成での DuckDB の実行が可能となります。DuckDB の理念に基づき、Quack もセットアップが容易で、HTTP という確立された技術の上に構築されています。また高速度であり、バッチ処理から小規模なトランザクションまで多様なワークロードをサポートします。
バックグラウンド:データベースアーキテクチャの歴史
データベースが登場した当初は、「クライアント」と「サーバー」の区別は存在しませんでした。データベース全体が単一のコンピュータ上で動作していました。1980 年代半ば、Sybase が初めてデータベース「サーバー」と異なるコンピュータで動作する「クライアント」の概念を導入しました。その後の全てのデータベースシステムは、このクライアント・サーバーアーキテクチャと、相互通信を行うプロトコルを使用するという前提を抱くようになっています。これは利便性があり、データの変更可能な状態(ステート)をサーバー側に一元化し、複数のクライアントが同時にデータを読み書きできるようにするためです。ただし、この手法には欠点もあり、特にプロトコルによるオーバーヘッドが大きな問題となりました。(詳細については、過去に執筆したデータベースプロトコルに関する研究論文をご覧ください。)
もちろん、クライアント・サーバーアーキテクチャへの異議申し立て者は常に存在しました。代表的な例として 2000 年の SQLite と、そして 2019 年にリリースされた DuckDB が挙げられます。私たちはプロセス内アーキテクチャ(クライアント・サーバーなし、プロトコルなし、低レベルの API コールだけの状態)の導入について大きな反響を得ました。これは、データサイエンスなどのインタラクティブなユースケース(例:Python ノートブックでデータを分析し、同じプロセス上で動作する DuckDB インスタンスがデータを管理するケース)や、既存アプリケーションに SQL 機能を追加するための「接着(アドオン)」的なユースケースにおいて非常に成功しました。
一方で、同一のデータベースファイルを複数のプロセスから同時に修正しようとするユースケースでは、このプロセス内システムは「あまりうまく機能しませんでした」。例えば、多くのプロセスが監視データを収集しながらインサートを行い、その間にも同じテーブルをクエリしてダッシュボードを動かすといった状況です。これは技術的に実現できないことがあり、主に DuckDB がメインメモリ上に状態を保持しており、複数のプロセスが同時に変更を行う場合、その状態の同期(コンカレンシーコントロール)が必要不可欠であるためです。
回避策はいくつか存在しました。当然のことながら、DuckDB データベースインスタンスを保持するプロセスと、他のプロセスからクエリやデータの挿入を受け付けるサービスを提供する RPC(リモートプロシージャコール)アプローチを組み合わせることも可能です。また、Arrow Flight SQL プロトコルなどを使用して DuckDB にクライアント・サーバー機能を後付けした複数のプロジェクトも存在します。MotherDuck も独自のクライアント・サーバープロトコルを持っています。もちろん、PostgreSQL といった従来のデータベースシステムへの切り替えも常に選択肢の一つです(pg_duckdb などの拡張機能を使用して PostgreSQL 上で「EleDucken」として DuckDB を実行することも可能)。
人々が DuckDB にクライアント・サーバー解決策を組み付けるために考案した無数の回避策は、少なくともこれが人々の関心事であることを私たちに気づかせました。DuckDB はユニバーサルなデータ処理ツールとして捉えています。プロセス内機能に加え、クライアント・サーバープロトコルがあることでも問題ありません。さらにそれによって DuckDB が有用になる新たなケースが解放されるのであれば素晴らしいことです!結局、私たちはユーザー体験(UX)に深く関心を持ち、アーキテクチャ的な議論よりも重要だと考えています。そのため、ある日ようやく口を開き、本日発表いたします:
DuckDB 用「Quack プロトコル」の導入
2 匹(またはそれ以上)の鴨が互いに話したい場合、どうしますか?彼らは「クアック(呱呱音)」をするのです!したがって、DuckDB インスタンス同士が会話できるプロトコルを「Quack」と呼ぶのは非常に自然です。私たちは 2026 年に、過去のレガシーの包袱に縛られることなく、クリーンなデータベースプロトコルから設計する機会を得ました。これは大きな贅沢です。既存のプロトコル(より最近の Arrow Flight SQL など)から学ぶことができました。内部動作の説明に入る前に、まずはユーザー視点での動作を見てみましょう。
まず 2 つの DuckDB インスタンスが必要です。そう、DuckDB はクライアントとしてもサーバーとしても機能します!2 つのインスタンスは地球の反対側にあるコンピュータ上でも、あなたのラップトップ上の 2 つの異なるターミナルウィンドウでも構いません。まずは両方の DuckDB インスタンスに Quack 拡張モジュールをインストールする必要があります。現時点では、Quack は
core_nightly リポジトリにあります。現在のリリースバージョン v1.5.2 でも利用可能です:
DuckDB #1(サーバー側)
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 #2(クライアント側)
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')が表示されます。まるで魔法のようです!また、ローカルインスタンスからリモートインスタンスにデータをコピーすることも可能です:
-- ステップ 1 (DuckDB #2) CREATE TABLE remote.hello2 AS FROM VALUES ('world2') v(s);
同様に、DuckDB #1 の出力には 'world2' が表示されるはずです。もちろんこれらは最も基本的な例です。テーブルはより複雑で、クエリもより複雑で、データボリュームも非常に大きくなる可能性があります(後述)。また、
query 関数を使用して、完全に SQL スタンダードな文をリモートに配信することも可能であり、大規模データセットに対する複雑なクエリや、リモートで実行される内容をより詳細に制御したい場合に適しています:
-- 複雑なクエリの実行 (DuckDB #2) FROM remote.query( 'SELECT s FROM hello' );
さらに多くの機能がここにあります。詳しくはドキュメントをご覧ください。
プロトコル設計
HTTP ベース
Quack は、CERN でのごく当初の頃から Hypertext Transfer Protocol(HTTP)を基盤としています。HTTP は TCP とそれ以下の層の上に事実上のプロトコルレイヤーとなっており、メッセージストリームの効率的な伝送に最適化されたスタック全体を持っています。適切に実装されれば、プロトコルのオーバーヘッドは驚くほど低いです。ロードバランシング、認証、ファイアウォール、インサイド検知など、誰もが HTTP の扱い方を理解しています。2026 年にデータベースプロトコルを HTTP の上に構築しないのは間違いです。HTTP はまた、DuckDB-Wasm 配布版が Quack をネイティブに話すことを可能にし、ブラウザ上で動作する DuckDB が EC2 サーバー上の DuckDB インスタンスと直接接続することを可能にします。
リクエスト・レスポンス パターン
Quack 上での相互作用は常にクライアント主導のリクエスト・レスポンスパターンに基づいています。Quack メッセージには、上記のトークンによる認証を含むコネクションリクエストが含まれます(下部の詳細な認証と承認の手順も参照)。その後のメッセージは、クエリの実行と最初の部分のレスポンスの返送に関するリクエストであり、大規模な結果を取得し続ける追跡メッセージです。これらは複数スレッドで並列に取得される可能性があります。
シリアライゼーション
リクエストとレスポンスは、新しい MIME タイプ
application/duckdb を使用してエンコードされます。このエンコーディングは、複合構造(データ型や結果セットなど)のための DuckDB の内部効率的なシリアライゼーションプリミティブを活用します。私たちは何年にもわたって Write-Ahead Log (WAL) ファイルのために同じプリミティブを使用してきたため、これらはかなり良く最適化されており、実戦でテスト済みです。
暗号化(エンクリプション)
「ただ動くように」したい一方で、データベースを悪意のあるインターネットに直接接続するセキュリティの悪夢に対する警戒心もあります(以前のような感覚から)。そのため、Quack はデフォルトでサーバー起動時にランダムな認証トークンを生成し、それをクライアントに渡します。さらに、Quack サーバーはデフォルトでは localhost しかバインドしません(当然ながら上書き可能です)。Quack はデフォルトで SSL を使用せず、localhost 通信のためにこれだけのインフラストラクチャを持ち込み依存関係を添加するのは少し非現実的だからです。DuckDB Quack エンドポイントを実際にインターネットに公開することをお勧めしません。代わりに、世界中へ Quack を露出させる場合は一般的な HTTP エンドポイント(nginx など)を使用し、SSL を終端させる(例:Let's Encrypt で)ことを強くお勧めします。Quack クライアントは非ローカル接続では SSL が有効であると仮定しており、これは上書きできます。詳細はドキュメントをご参照ください。
ラウンドトリップ回数の最適化
プロトコルのラウンドトリップ数(リクエスト/レスポンスペア)を最適化する事に努めました。接続後、クエリは単一のラウンドトリップで完全に処理できます。これはレイテンシ感受性環境に対する重要な最適化です。同時に、Quack は効率的なバッチ結果転送に非常に最適化されています。私たちが知る限り、Quack はソケットを介してテーブルを送るのに現在最も高速であり、数百万行のデータを数秒で転送できます。以下のベンチマーク結果をご覧ください。
認証と承認
データベースクエリの認証と承認は永遠に楽しさの源泉であり同時に複雑性の源です。おそらく私たちはすべてのユースケースをキャッチアップすることはできません(特に最初のリリースでは)。賢明なのは過信せず、慎重に進めることです。Quack では、DuckDB の拡張可能性の哲学につながる認証モデルを選択しました。すでに数百もの DuckDB 拡張モジュールがあります。Quack はデフォルトの認証メソッドと承認制限を持たない出荷ですが、どちらもユーザー提供コードで上書きできます。前述のように、Quack サーバーは起動時にランダムな認証トークンを生成します。クライアントが接続すると、認証文字列を提供します。サーバー側は認証コールバックを呼び出します。デフォルトでは、クライアントから提供されたトークンと起動前にランダムに生成されたトークンを比較します。ただし、このコールバックは設定で変更できます!LDAP ディレクトリクエリ、テキストファイル読み込み、または単なる運試しのような独自の認証関数を導入できます。同様に、承認関数も変更可能です。デフォルトの承認関数はすべてに対して「はい」と答えますが、クライアントが実行しようとする各クエリを検証し、使用された認証文字列に相関付けることができます。これらのコールバックは純粋な SQL マクロでも構いません!詳細はドキュメントをご参照ください。
デフォルトポート
デフォルトでは、Quack サーバーはポート 9494 で待ち受けします。94 という数字は Netscape Navigator がリリースされた年であることが容易に覚えられますように。
ベンチマーク
Quack プロトコルを示すための 2 つのベンチマークを設けました。これらのベンチマークは、Ubuntu on Arm を実行する AWS 仮想マシン上で実行されました。m8g.2xlarge インスタンスタイプを選択し、8 vCPUs と 32 GB の RAM、「最大 15 Gbps」のネットワーク帯域幅を備えています。クライアントとサーバーが同じデータセンター内にあるが異なるマシンのような現実世界のシナリオを作成しました。両方のインスタンスは同じ「可用性ゾーン」にあります。インスタンス間の Ping 時間は平均約 0.280 ms です。
バッチ転送(Bulk Transfer)
最初のベンチマークはバッチ転送をテストし、比較的大数の行をデータベースプロトコルで転送する場合です。上記にリンクした論文を読まれた方は、この場合は従来のデータベースプロトコルが苦労したケースを知っています。広範な PostgreSQL プロトコルと新しい Arrow Flight SQL プロトコルの 2 システムと比較します。Arrow Flight は GizmoSQL サーバー(内部で DuckDB も使用)によって提供されます。TPC-H lineitem テーブルの増加する行数をすべて、76 GB の CSV 形式での壮観な 6000 万行まで転送し、5 回の実行の中央値壁時計時間を報告します。モダンなバッチ指向プロトコルが PostgreSQL プロトコルを大きく凌駕することを期待しています。
バッチ転送操作の所要時間(下がるほど良い)
| 行数 | DuckDB Quack | Arrow Flight | PostgreSQL |
|---|---|---|---|
| 100k | 0.07 s | 0.07 s | 0.20 s |
| 1M | 0.24 s | 0.38 s | 2.20 s |
| 10M | 0.89 s | 2.90 s | 25.64 s |
| 60M | 4.94 s | 17.40 s | 158.37 s |
Quack がバッチ結果セット転送に優れていることがわかります。6000 万行も 5 秒未満で転送します!専用として設計された Arrow Flight SQL プロトコルですらここには追いつくことができず、Postgres の行ベースのプロトコルは一般に非常に絶望的です。
公平のために言及する必要がありますが、標準的な PostgreSQL クライアントはマルチスレッドでリードを並列化しません。しかし Quack と Arrow はできます!(恥知らずなプラグ:DuckDB の PostgreSQL クライアントも一部のケースでこれを行うことができます!)
小規模な書き込み(Small Writes)
2 番目のベンチマークは小規模なアペンド(追加)をテストします。これは、例として観測可能性データを単一の中央 DuckDB インスタンスに集約する場合のような一般的なユースケースです。データベースプロトコルを異なる方法でストレスをかけます。例えば、1 つのトランザクションを完了するためにクライアントとサーバー間のラウンドトリップが多数ある場合、不利になる可能性があります。これをテストするために、TPC-H lineitem テーブルと同じ構造を持つ空のテーブルを作成し、各行ごとの INSERT トランザクションでランダム化された値を挿入します。挿入された値は通常のある程度のベンチマークジェネレーターの分布に従います。この実験を 5 秒間、増加する並列スレッド数で行いました。この実験を 5 回繰り返し、中央値トランザクション/秒を報告しました。
トランザクションに高度に最適化されたシステムである PostgreSQL がこのベンチマークを支配することを期待します。また、バッチに最適化された Arrow Flight が特にうまくいかないことも期待します。
小規模な書き込みのスループット(上がるほど良い)
| スレッド数 | DuckDB Quack | Arrow Flight | PostgreSQL |
|---|---|---|---|
| 1 | 1,038 tx/s | 469 tx/s | 839 tx/s |
| 2 | 1,956 tx/s | 799 tx/s | 1,094 tx/s |
| 4 | 3,504 tx/s | 1,224 tx/s | 2,180 tx/s |
| 8 | 5,434 tx/s | 1,358 tx/s | 4,320 tx/s |
驚くべきことに、Quack は Postgres を凌駕し、最大約 5,500 トランザクション/秒のトランザクションレートを 8 つの並列スレッドまで達成していることが見られます。これ以上では、同じテーブルへの並列挿入あたりの現在の DuckDB の制限に達しました。PostgreSQL はここでより良くスケールしており、これは近い将来私たちが調査するべきことです。Arrow Flight は Postgres の半分程度の速度であり、期待通りです。
ベンチマークスクリプトはオンラインで利用可能です。
結論
本日、DuckDB 拡張モジュールとしての初期実装と共に DuckDB 用のクライアント・サーバープロトコルである Quack をリリースしました。Quack は複数の別々のプロセス(ローカルまたはリモート)が互いをロックせずに並列にテーブルの内容を修正できる完全なマルチプレイヤー体験を解放します。これは Already DuckLake でも達成できた一部ですが、Quack はこれをはるかにシンプルにし、はるかに高いパフォーマンスを提供します。
ユースケース
Quack により、DuckDB は状態の中央化が超ローカル(In-process)クエリよりも重要な広範な新しいユースケースで有用になりました。データの常にローカルではないことはすでにデータ湖(Data Lake)の上昇を通じて学びました。湖の話になりますが、Quack も DuckLake に統合され、DuckDB 自体がリモートアクセシブルなカタログサーバーになる予定です。これはデータインライニングなどの新たな機能を解放します。さらに質問がある場合は Quack FAQ をご参照ください。
全体として、DuckDB はインタラクティブ分析のためのプロセス内データベースという初期のニッチから、現代データアーキテクチャの中核的なビルディングブロックへと進んでいます。Quack で遊んでおり、あなたたちが何を作ってくれるか非常に楽しみです。Quack が改善される方法についての提案があればお知らせください!そしてヘイ、MythBusters は鴨のクアックが反響することをすでに証明しているので、どのようなノイズが生じるか見てみましょう。
次のステップ
もちろんまだやるべきことがたくさんあります。まず、Quack を DuckLake に統合し、リモート DuckDB サーバーを DuckLake カタログとして使用できるようになるようにします!これは特にインライニングでパフォーマンスを大幅に向上させるでしょう。次に、数ヶ月間で Quack を研鑽し、秋の年にくる v2.0 と共に最初のプロダクションリリースを発表する予定です。例えば、必要に応じて自動的に Quack 拡張モジュールのインストールと読み込みを有効にする計画です。新しいパーサーを使用すると、DuckDB からリモート SQL データベースへの対話のためのシンタックスも改善予定です。コア DuckDB の側では、トランザクション/秒を大幅に増加させて並列スレッド 8 つを超えてトランザクションをスケールできるようにする作業を計画しています。
さらに、認証と承認を超えて Quack プロトコルへの拡張について考えています。例えば、DuckDB 拡張モジュールが新しいプロトコルメッセージを追加し、それらを処理するコードを追加できるようにします。また、DuckDB インスタンスの変更を他のサーバーに複製するためのレプリケーションプロトコルを添加することを考えており、例として read replicas のクラスターを設定するために使用できます。
Quack についてさらに学び、初期の採用状況について聞くには、6 月 24 日のコミュニティカンファレンス DuckCon #7 に参加してください。DuckCon は DuckDB の共創作者によって行われる「State of the Duck」講演で始まります。現地参加でも YouTube のオンラインストリームでの視聴も可能です。
PS: Quack プロジェクト専用のページがあり、必ず訪問してください。
謝辞
MotherDuck の Boaz Leskes 氏に MotherDuck プロトコルの構築からの教訓を共有していただきありがとうございます。また、GizmoSQL / GizmoData の Philip Moore 氏にはすでにこの道を開いてくれており、クライアント・サーバー型 DuckDB は非常に価値があることを見せていただきありがとうございます。
アペンディクス:なぜ Arrow Flight SQL を使わないのか?
私たちが既存の Arrow Flight SQL プロトコルを使用しなかった理由について、部屋の象のうちの少数に触れる必要があります:なぜそれを使わないのですか?そこにあります。利用可能です。既存の実装があります。Arrow と ADBC といった関連プロジェクトには価値を見出します:ODBC や JDBC よりも前にデータをシステム間で交換するための摩擦を軽減することを目指す代替 API です。それはうまく機能します。
しかし、Arrow を内部構造に使用する事への警戒心もあります。DuckDB のクエリ中間体の内部構造は Arrow といくつかの点では似ていますが、他の点ではかなり異なります。データシステムの革新を続けるために、外部で制御されているフォーマットによって制限されることはできません。これが Quack で独自のシリアライゼーションを使用する理由です。新しいデータ型やプロトコルメッセージを追加したい場合、明日に配信できます。
深く根底には、Arrow Flight SQL における運命的な設計決定の一つがあります:すべてのクエリは少なくとも 2 つのプロトコルラウンドトリップ(CommandStatementQuery および DoGet)を必要とします。これは、特に高レイテンシー環境での小規模な更新のような場合(上記の 2 番目の実験のような)、理想的ではありません。前述のとおり、Quack を単一のラウンドトリップでクエリ実行と結果フェッチできるように設計しました。