同期モードで多数の小さなバッチを送信することは推奨されません。多くのパーツが作成される原因になるためです。これにより、クエリ性能の低下や “too many part” エラーにつながります。
async_insert 設定によって制御されます。
非同期挿入は HTTP と native TCP の両方のインターフェイスでサポートされています。
有効化されている場合 (async_insert = 1) 、INSERT はバッファリングされ、次のフラッシュ条件のいずれかが満たされた時点でのみ disk に書き込まれます。
- バッファが指定されたデータサイズに達する (
async_insert_max_data_size、デフォルトは 100 MiB) 。 - 時間しきい値が経過する (
async_insert_busy_timeout_ms、デフォルトは 200 ms、Cloud では 1000 ms) 。 - INSERT クエリの最大数が蓄積される (
async_insert_max_query_number、デフォルトは 450) 。
戻りモードの選択
wait_for_async_insert 設定によってさらに細かく制御できます。
1 (デフォルト) に設定すると、ClickHouse はデータが正常にディスクにフラッシュされたあとでのみ insert の受け付けを通知します。これにより高い永続性が確保され、error 処理もシンプルになります。フラッシュ中に問題が発生した場合は、その error がクライアントに返されます。このモードは、ほとんどの本番環境、とくに insert の失敗を確実に追跡する必要がある場合に推奨されます。
ベンチマーク では、適応的な insert と安定した part 作成動作により、200 クライアントでも 500 クライアントでも、高い並行度でも良好にスケールすることが示されています。
wait_for_async_insert = 0 を設定すると、「fire-and-forget」モードが有効になります。この場合、server はデータが storage に書き込まれるのを待たず、バッファ に格納された時点で insert の受け付けを通知します。
これにより、超低 latency の insert と最大限の throughput が得られるため、高速に流入し、重要度の低いデータに適しています。ただし、これにはトレードオフがあります。データが永続化される保証はなく、error が表面化するのはフラッシュ時だけで、失敗した insert のための dead-letter queue もありません。障害を追跡するには、事後的に サーバーログ とシステムテーブルを調査する必要があります。このモードは、workload がデータ損失を許容できる場合にのみ使用してください。
ベンチマークではさらに、バッファ のフラッシュ頻度が低い場合 (たとえば 30 Seconds ごと) には、part の大幅な削減と CPU 使用率の低下も示されていますが、気づかれないまま失敗するリスクは残ります。
非同期挿入を使用する場合は、async_insert=1,wait_for_async_insert=1 を使うことを強く推奨します。wait_for_async_insert=0 の使用は非常に危険です。error が発生しても INSERT クライアントがそれを認識できない可能性があるうえ、service の信頼性を確保するために ClickHouse server 側で書き込みを抑制し、backpressure をかける必要がある状況でも、クライアントが高速な書き込みを続けることで過負荷を引き起こすおそれがあるためです。
適応型非同期 INSERT
async_insert_use_adaptive_busy_timeout) が使用されます。固定のフラッシュ間隔ではなく、受信データのレートに応じて、タイムアウトが最小値 (async_insert_busy_timeout_min_ms、デフォルトは 50 ms) から最大値 (async_insert_busy_timeout_max_ms、デフォルトは 200 ms、Cloud では 1000 ms) までの範囲で動的に調整されます。
データが高頻度で到着する場合、より早くフラッシュしてエンドツーエンドのレイテンシを抑えるため、タイムアウトは最小値寄りに保たれます。データがスパースな場合は、より大きなバッチを蓄積できるよう、最大値に向かって長くなります。これは、固定の長いタイムアウトを設定すると、フラッシュ可能なデータがすでに揃っていてもクライアントがその間ずっと待たされてしまうデフォルトモード (wait_for_async_insert=1) で特に有効です。
エラー処理
wait_for_async_insert=1) では、エラーはクライアントに返されます。fire-and-forget モードでは、エラーはサーバーログと system.asynchronous_inserts テーブルに書き込まれます。
フラッシュが実行されるたびに、バッファ内の異なる各パーティションキーの値ごとに少なくとも 1 つのパーツが作成されます。パーティションキーのないテーブルであっても、バッファされたデータが max_insert_block_size (デフォルトは約 100 万行) を超える場合、1 回のフラッシュで複数のパーツが生成されることがあります。
非同期 INSERT を使用していても、パーティション化キーのカーディナリティが高い場合は、“パーツが多すぎる” エラーが発生することがあります。
重複排除と信頼性
非同期挿入の有効化
-
ユーザーレベルで非同期挿入を有効にします。この例ではユーザー
defaultを使用しています。別のユーザーを作成した場合は、そのユーザー名に置き換えてください。 -
INSERT クエリの SETTINGS 句を使用して、非同期挿入の設定を指定することもできます。
-
ClickHouse のプログラミング言語クライアントを使用する場合は、接続パラメーターとして非同期挿入の設定を指定することもできます。
たとえば、ClickHouse Cloud への接続に ClickHouse Java JDBCドライバーを使用する場合、JDBC 接続文字列では次のように指定できます。
非同期挿入は
INSERT INTO ... SELECT クエリには適用されません。挿入に SELECT 句が含まれている場合、async_insert 設定に関係なく、クエリは常に同期的に実行されます。シャットダウン時にバッファをフラッシュする
Bufferテーブルとの比較
- DDL の変更は不要です。 非同期挿入は透過的に動作するため、追加のテーブルを作成するのではなく、設定を有効にするだけで利用できます。
- クエリ形状ごとのバッファリング。 非同期挿入では、一意のクエリ形状と設定の組み合わせごとに個別のバッファが維持されるため、きめ細かな フラッシュ ポリシーを適用できます。Buffer tables では、ターゲットテーブルごとに 1 つのバッファを使用します。
- 耐久性。 デフォルトモード (
wait_for_async_insert=1) では、クライアントに確認応答が返される前に、データがディスクに書き込まれたことが確認されます。Buffer tables は fire-and-forget 型で動作するため、クラッシュ時にはバッファ内のデータが失われます。 - クラスターでの動作。 クラスターでは、非同期挿入のバッファはノードごとに維持されます。Buffer tables では、各ノードで明示的に作成する必要があります。