メインコンテンツまでスキップ
メインコンテンツまでスキップ

ClickHouse Rust Client

ClickHouseに接続するための公式Rustクライアントで、元々はPaul Loydによって開発されました。クライアントのソースコードはGitHubリポジトリで入手できます。

概要

  • 行のエンコーディング/デコーディングに serde を使用します。
  • serde 属性をサポートしています: skip_serializing, skip_deserializing, rename
  • HTTPトランスポート上でRowBinaryフォーマットを使用します。
    • TCP経由でNativeへ切り替える計画があります。
  • TLSをサポートしています(native-tls および rustls-tls 機能を介して)。
  • 圧縮と解凍をサポートしています(LZ4)。
  • データの選択または挿入、DDLの実行、クライアント側のバッチ処理のためのAPIを提供します。
  • 単体テスト用の便利なモックを提供します。

インストール

クレートを使用するには、Cargo.tomlに以下を追加します:

詳細は:crates.ioページを参照してください。

Cargo機能

  • lz4(デフォルトで有効) — Compression::Lz4 および Compression::Lz4Hc(_) バリアントを有効にします。これが有効のときは、デフォルトで Compression::Lz4WATCH を除くすべてのクエリに使用されます。
  • native-tlsHTTPS スキーマを持つURLを hyper-tls を介してサポートし、OpenSSLにリンクします。
  • rustls-tlsHTTPS スキーマを持つURLを hyper-rustls を介してサポートし、OpenSSLにリンクしません。
  • inserterclient.inserter() を有効にします。
  • test-util — モックを追加します。詳細はを参照してください。これはdev-dependenciesでのみ使用してください。
  • watchclient.watch 機能を有効にします。詳細は該当するセクションを参照してください。
  • uuiduuidクレートと連携するための serde::uuid を追加します。
  • timetimeクレートと連携するための serde::time を追加します。
参考

HTTPS URLを介してClickHouseに接続する場合は、native-tls または rustls-tls 機能のいずれかを有効にする必要があります。 両方が有効な場合、rustls-tls 機能が優先されます。

ClickHouseバージョンの互換性

クライアントは、LTSまたはそれ以降のバージョンのClickHouse、及びClickHouse Cloudと互換性があります。

ClickHouseサーバーがv22.6以前の場合、RowBinaryは一部の稀なケースで不正に処理されます。 v0.11以上を使用し、wa-37420機能を有効にすることでこの問題を解決することができます。注意:この機能は新しいClickHouseバージョンでは使用しないでください。

クライアントの使用法に関するさまざまなシナリオをカバーすることを目指して、クライアントリポジトリにを用意しています。概要は例のREADMEにあります。

例や以下のドキュメントに不明点や不足があれば、遠慮なくお問い合わせください

使用法

注記

ch2rsクレートは、ClickHouseから行タイプを生成するのに便利です。

クライアントインスタンスの作成

ヒント

作成したクライアントを再利用するか、それらをクローンして、基盤のhyper接続プールを再利用してください。

HTTPSまたはClickHouse Cloud接続

HTTPSは rustls-tls または native-tls Cargo機能のいずれかで機能します。

次に、通常通りクライアントを作成します。この例では、環境変数を使用して接続の詳細を格納します:

参考

URLはプロトコルとポートの両方を含む必要があります。例: https://instance.clickhouse.cloud:8443

詳細は以下もご覧ください:

行の選択

  • プレースホルダー ?fieldsno, nameRow のフィールド)に置き換えられます。
  • プレースホルダー ? は、次の bind() 呼び出しでの値に置き換えられます。
  • 一番最初の行またはすべての行を取得するために、便利な fetch_one::<Row>() および fetch_all::<Row>() メソッドを使用できます。
  • テーブル名をバインドするには、sql::Identifier を使用できます。

注意:レスポンス全体がストリームされるため、カーソルは一部の行を生成した後でエラーを返す可能性があります。これが発生した場合は、サーバー側でレスポンスバッファリングを有効にするためにquery(...).with_option("wait_end_of_query", "1")を試してみてください。詳細はこちらbuffer_sizeオプションも役立ちます。

危険

行を選択する際に wait_end_of_query を使用する場合は注意が必要です。サーバー側のメモリ消費が増加し、全体のパフォーマンスが低下する可能性があります。

行の挿入

  • end() が呼ばれない場合、INSERT は中止されます。
  • 行は進行状況に応じてストリームとして送信されて、ネットワーク負荷を分散させます。
  • ClickHouseは、すべての行が同じパーティションに収まり、その数がmax_insert_block_sizeより少ない場合にのみバッチを原子性で挿入します。

非同期挿入(サーバー側のバッチ処理)

ClickHouseの非同期挿入を使用して、着信データのクライアント側のバッチ処理を避けることができます。これには、insertメソッド(またはクライアントインスタンス自体)にasync_insertオプションを提供するだけで済みます。

詳細は:

インサーター機能(クライアント側のバッチ処理)

inserter Cargo機能が必要です。

  • Inserter は、いずれかの閾値(max_bytes, max_rows, period)に達した場合、commit() でアクティブな挿入を終了します。
  • アクティブな INSERT の終了間隔は、並列インサーターによる負荷スパイクを回避するために with_period_bias を使用して調整できます。
  • Inserter::time_left() を使用して現在の期間の終了時刻を検出できます。ストリームがアイテムをほとんど発生させない場合は、制限を確認するために Inserter::commit() を再度呼び出してください。
  • 時間の閾値は、quantaクレートを利用して inserter を高速化します。test-util が有効な場合は使用されません(この場合、カスタムテストで tokio::time::advance() で時間を管理できます)。
  • commit() 呼び出しの間にあるすべての行は、同じ INSERT ステートメントに挿入されます。
危険

挿入を終了/完了したい場合はフラッシュするのを忘れないでください:

DDLの実行

単一ノードのデプロイメントでは、次のようにDDLを実行するだけで十分です:

ただし、ロードバランサーやClickHouse Cloudと共に使用されるクラスター配置では、すべてのレプリカにDDLが適用されるのを待つことをお勧めします。これは次のように実行できます:

ClickHouse設定

with_optionメソッドを使用して、さまざまなClickHouse設定を適用できます。例えば:

queryに加えて、insertinserterメソッドでも同様に機能します。また、グローバル設定をすべてのクエリに適用するためにClientインスタンスでも同じメソッドを呼び出すことができます。

クエリID

.with_optionを使用して、ClickHouseクエリログ内のクエリを識別するためのquery_idオプションを設定できます。

queryの他、insertおよびinserterメソッドでも同様に機能します。

危険

query_idを手動で設定する場合は、それがユニークであることを確認してください。UUIDが良い選択です。

詳細は、query_idの例をクライアントリポジトリで見てください。

セッションID

query_idと同様に、同じセッションでステートメントを実行するためにsession_idを設定できます。session_idはクライアントレベルでグローバルに設定することも、queryinsert、またはinserterの呼び出しごとに設定することもできます。

危険

クラスター配置では「スティッキーセッション」がないため、特定のクラスターノードに接続してこの機能を適切に利用する必要があります。ラウンドロビンのロードバランサーは、連続するリクエストが同じClickHouseノードによって処理されることを保証しません。

詳細は、session_idの例をクライアントリポジトリで見てください。

カスタムHTTPヘッダー

プロキシ認証を使用する場合やカスタムヘッダーを渡す必要がある場合は、次のようにします:

詳細は、カスタムHTTPヘッダーの例をクライアントリポジトリで見てください。

カスタムHTTPクライアント

これは、基盤のHTTP接続プール設定を調整するのに役立ちます。

危険

この例は古典的なHyper APIに依存しており、将来変更される可能性があります。

詳細は、カスタムHTTPクライアントの例をクライアントリポジトリで見てください。

データ型

参考

追加の例については、次をご覧ください:

  • (U)Int(8|16|32|64|128)は、対応する (u|i)(8|16|32|64|128)型またはそれらの新タイプにマップされます。
  • (U)Int256は直接はサポートされませんが、回避策があります。
  • Float(32|64)は、対応する f(32|64)型またはそれらの新タイプにマップされます。
  • Decimal(32|64|128)は、対応する i(32|64|128)型またはそれらの新タイプにマップされます。符号付き固定小数点数の実装には、fixnumを使用すると便利です。
  • Booleanは、boolまたはそれに関する新タイプにマップされます。
  • Stringは、任意の文字列またはバイト型(例:&str, &[u8], String, Vec<u8>またはSmartString)にマップされます。新タイプもサポートされています。バイトを保存するには、serde_bytesを使用することを考慮してください。これはより効率的です。
  • FixedString(N)はバイトの配列としてサポートされます。例:[u8; N]
  • Enum(8|16)は、serde_reprを使用してサポートされています。
  • UUIDは、uuid::Uuidserde::uuidを使用してマップされます。uuid機能が必要です。
  • Dateは、u16またはそれに関する新タイプにマップされ、1970-01-01から経過した日数を表します。また、time::Dateserde::time::dateを使用してサポートされています。このためにはtime機能が必要です。
  • Date32は、i32またはそれに関する新タイプにマップされ、1970-01-01から経過した日数を表します。また、time::Dateserde::time::date32を使用してサポートされています。このためにはtime機能が必要です。
  • DateTimeは、u32またはそれに関する新タイプにマップされ、UNIXエポックから経過した秒数を表します。また、time::OffsetDateTimeserde::time::datetimeを使用してサポートされています。このためにはtime機能が必要です。
  • DateTime64(_)は、i32またはそれに関する新タイプにマップされ、UNIXエポックから経過した時間を表します。また、time::OffsetDateTimeserde::time::datetime64::*を使用してサポートされます。このためにはtime機能が必要です。
  • Tuple(A, B, ...)は、(A, B, ...)またはそれに関する新タイプにマップされます。
  • Array(_)は、任意のスライス(例:Vec<_>&[_])にマップされます。新タイプもサポートされています。
  • Map(K, V)Array((K, V))のように振る舞います。
  • LowCardinality(_)はシームレスにサポートされています。
  • Nullable(_)は、Option<_>にマップされます。clickhouse::serde::*ヘルパーのためには::optionを追加してください。
  • Nestedは、複数の配列を提供してリネームすることでサポートされています。
  • Geo 型はサポートされます。Pointはタプル(f64, f64)のように振る舞い、他の型は点のスライスです。
  • VariantDynamic、(新しい) JSON データ型はまだサポートされていません。

モック

このクレートは、CHサーバーのモック作成とDDL、SELECTINSERTWATCHクエリのテストのためのユーティリティを提供します。この機能はtest-util機能を通じて有効にできます。dev-dependencyとしてのみ使用してください。

を参照してください。

トラブルシューティング

CANNOT_READ_ALL_DATA

CANNOT_READ_ALL_DATAエラーの最も一般的な原因は、アプリケーション側の行定義がClickHouseのそれに一致しないことです。

以下のテーブルを考えてみましょう:

その後、EventLogがアプリケーション側で型が一致しないように定義されている場合(例):

データを挿入すると、次のエラーが発生することがあります:

この例では、EventLog構造体の正しい定義で解決できます:

知られている制限

  • VariantDynamic、(新しい) JSONデータ型はまだサポートされていません。
  • サーバー側のパラメータバインディングはまだサポートされていません。この件に関してはこの問題で追跡しています。

お問い合わせ

質問がある場合や支援が必要な場合は、Community SlackまたはGitHubの問題を通じてお気軽にお問い合わせください。