ClickHouse Rustクライアント
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—hyper-tlsを通じてHTTPSスキーマのURLをサポートし、OpenSSLにリンクします。rustls-tls—hyper-rustlsを通じてHTTPSスキーマのURLをサポートし、OpenSSLにリンクしません。inserter—client.inserter()を有効にします。test-util— モックを追加します。詳細はこちらの例をご覧ください。これはdev-dependenciesでのみ使用してください。watch—client.watch機能を有効にします。詳細は対応するセクションを参照してください。uuid— uuidクレートで作業するためにserde::uuidを追加します。time— timeクレートで作業するためにserde::timeを追加します。
ClickHouseにHTTPS URLを介して接続する場合、native-tlsまたはrustls-tlsのいずれかの機能を有効にする必要があります。両方が有効にされている場合は、rustls-tls機能が優先されます。
ClickHouseバージョンの互換性
このクライアントはLTSまたはそれ以降のバージョンのClickHouseと、ClickHouse Cloudに対応しています。
v22.6より古いClickHouseサーバーは、行バイナリを一部の稀なケースで不正確に処理します。 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接続にも適用可能です。
行の選択
- プレースホルダー
?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機能(クライアント側バッチ処理)
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を使用したクラスター展開では、wait_end_of_queryオプションを使用して、すべてのレプリカでDDLが適用されるのを待つことをお勧めします。これは次のように行うことができます。
ClickHouse設定
with_optionメソッドを使用して、さまざまなClickHouse設定を適用できます。例として:
queryに加えて、insertおよびinserterメソッドでも同様に機能します。また、クライアントインスタンス上で同じメソッドを呼び出すことで、すべてのクエリに対してグローバル設定を設定できます。
クエリ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は、serde::uuidを使用してuuid::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機能を使用して有効化できます。これは開発依存性としてのみ使用してください。
例をご覧ください。
トラブルシューティング
CANNOT_READ_ALL_DATA
CANNOT_READ_ALL_DATAエラーの最も一般的な原因は、アプリケーション側の行定義がClickHouseの定義と一致しないことです。
以下のテーブルを考慮してください:
次に、アプリケーション側でEventLogが不一致の型で定義されていると、例えば以下のようになります:
データを挿入すると、次のエラーが発生することがあります:
この例では、EventLog構造体の正しい定義によって解決されます:
既知の制限
Variant、Dynamic、(新しい)JSONデータ型はまだサポートされていません。- サーバー側のパラメータバインディングはまだサポートされていません。これに関してはこの問題で進捗を追跡できます。
お問い合わせ
質問や支援が必要な場合は、Community SlackまたはGitHub issuesを通じてお気軽にお問い合わせください。