ClickHouse Rust Client
ClickHouseに接続するための公式Rustクライアントで、元々はPaul Loydによって開発されました。クライアントのソースコードはGitHubリポジトリで入手できます。
概要
- 行のエンコーディング/デコーディングに
serde
を使用します。 serde
属性をサポートしています:skip_serializing
,skip_deserializing
,rename
。- HTTPトランスポート上で
RowBinary
フォーマットを使用します。- TCP経由で
Native
へ切り替える計画があります。
- TCP経由で
- TLSをサポートしています(
native-tls
およびrustls-tls
機能を介して)。 - 圧縮と解凍をサポートしています(LZ4)。
- データの選択または挿入、DDLの実行、クライアント側のバッチ処理のためのAPIを提供します。
- 単体テスト用の便利なモックを提供します。
インストール
クレートを使用するには、Cargo.toml
に以下を追加します:
詳細は:crates.ioページを参照してください。
Cargo機能
lz4
(デフォルトで有効) —Compression::Lz4
およびCompression::Lz4Hc(_)
バリアントを有効にします。これが有効のときは、デフォルトでCompression::Lz4
がWATCH
を除くすべてのクエリに使用されます。native-tls
—HTTPS
スキーマを持つURLをhyper-tls
を介してサポートし、OpenSSLにリンクします。rustls-tls
—HTTPS
スキーマを持つURLをhyper-rustls
を介してサポートし、OpenSSLにリンクしません。inserter
—client.inserter()
を有効にします。test-util
— モックを追加します。詳細は例を参照してください。これはdev-dependencies
でのみ使用してください。watch
—client.watch
機能を有効にします。詳細は該当するセクションを参照してください。uuid
— uuidクレートと連携するためのserde::uuid
を追加します。time
— timeクレートと連携するための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
。
詳細は以下もご覧ください:
- ClickHouse CloudのHTTPS使用例は、オンプレミスのHTTPS接続にも適用されるはずです。
行の選択
- プレースホルダー
?fields
はno, name
(Row
のフィールド)に置き換えられます。 - プレースホルダー
?
は、次の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
に加えて、insert
やinserter
メソッドでも同様に機能します。また、グローバル設定をすべてのクエリに適用するためにClient
インスタンスでも同じメソッドを呼び出すことができます。
クエリID
.with_option
を使用して、ClickHouseクエリログ内のクエリを識別するためのquery_id
オプションを設定できます。
query
の他、insert
およびinserter
メソッドでも同様に機能します。
query_id
を手動で設定する場合は、それがユニークであることを確認してください。UUIDが良い選択です。
詳細は、query_idの例をクライアントリポジトリで見てください。
セッションID
query_id
と同様に、同じセッションでステートメントを実行するためにsession_id
を設定できます。session_id
はクライアントレベルでグローバルに設定することも、query
、insert
、または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::Uuid
にserde::uuid
を使用してマップされます。uuid
機能が必要です。
IPv6
は、std::net::Ipv6Addr
にマップされます。IPv4
は、std::net::Ipv4Addr
にserde::ipv4
を使用してマップされます。
Date
は、u16
またはそれに関する新タイプにマップされ、1970-01-01
から経過した日数を表します。また、time::Date
もserde::time::date
を使用してサポートされています。このためにはtime
機能が必要です。
Date32
は、i32
またはそれに関する新タイプにマップされ、1970-01-01
から経過した日数を表します。また、time::Date
もserde::time::date32
を使用してサポートされています。このためにはtime
機能が必要です。
DateTime
は、u32
またはそれに関する新タイプにマップされ、UNIXエポックから経過した秒数を表します。また、time::OffsetDateTime
もserde::time::datetime
を使用してサポートされています。このためにはtime
機能が必要です。
DateTime64(_)
は、i32
またはそれに関する新タイプにマップされ、UNIXエポックから経過した時間を表します。また、time::OffsetDateTime
もserde::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)
のように振る舞い、他の型は点のスライスです。
Variant
、Dynamic
、(新しい)JSON
データ型はまだサポートされていません。
モック
このクレートは、CHサーバーのモック作成とDDL、SELECT
、INSERT
、WATCH
クエリのテストのためのユーティリティを提供します。この機能はtest-util
機能を通じて有効にできます。dev-dependencyとしてのみ使用してください。
例を参照してください。
トラブルシューティング
CANNOT_READ_ALL_DATA
CANNOT_READ_ALL_DATA
エラーの最も一般的な原因は、アプリケーション側の行定義がClickHouseのそれに一致しないことです。
以下のテーブルを考えてみましょう:
その後、EventLog
がアプリケーション側で型が一致しないように定義されている場合(例):
データを挿入すると、次のエラーが発生することがあります:
この例では、EventLog
構造体の正しい定義で解決できます:
知られている制限
Variant
、Dynamic
、(新しい)JSON
データ型はまだサポートされていません。- サーバー側のパラメータバインディングはまだサポートされていません。この件に関してはこの問題で追跡しています。
お問い合わせ
質問がある場合や支援が必要な場合は、Community SlackまたはGitHubの問題を通じてお気軽にお問い合わせください。