OpenTelemetryによるデータ収集の統合
あらゆる観測ソリューションは、ログやトレースを収集してエクスポートする手段を必要とします。この目的のために、ClickHouseはOpenTelemetry (OTel)プロジェクトを推奨しています。
"OpenTelemetryは、トレース、メトリクス、ログなどのテレメトリデータを作成および管理するために設計された観測フレームワークおよびツールキットです。"
ClickHouseやPrometheusとは異なり、OpenTelemetryは観測バックエンドではなく、テレメトリデータの生成、収集、管理、エクスポートに焦点を当てています。OpenTelemetryの初期の目的は、ユーザーが言語特有のSDKを使用して自分のアプリケーションやシステムを容易に計測できるようにすることでしたが、OpenTelemetryコレクターを介してログを収集することも含むように拡張されました。コレクターは、テレメトリデータを受信、処理、エクスポートするエージェントまたはプロキシです。
ClickHouse関連コンポーネント
OpenTelemetryは多数のコンポーネントで構成されています。データおよびAPIの仕様、標準化されたプロトコル、フィールド/カラムの命名規則を提供するだけでなく、OTelはClickHouseで観測ソリューションを構築するための基本的な2つの機能を提供します。
- OpenTelemetry Collectorは、テレメトリデータを受信、処理、エクスポートするプロキシです。ClickHouseを利用したソリューションは、ログ収集とイベント処理のためにこのコンポーネントを使用します。
- 言語SDKは、仕様、API、およびテレメトリデータのエクスポートを実装します。これらのSDKは、アプリケーションコード内でトレースが正しく記録されることを保証し、構成要素のスパンを生成し、メタデータを介してサービス間でコンテキストが伝播されることを確実にします。これにより、分散トレースが形成され、スパンが相関できるようになります。これらのSDKは、自動的に一般的なライブラリやフレームワークを実装するエコシステムによって補完されるため、ユーザーはコードを変更する必要がなく、即時の計測が得られます。
ClickHouseを利用した観測ソリューションは、これらのツールの両方を活用します。
ディストリビューション
OpenTelemetryコレクターには多数のディストリビューションがあります。ClickHouseソリューションに必要なfilelogレシーバーとClickHouseエクスポータは、OpenTelemetry Collector Contrib Distroにのみ存在します。
このディストリビューションは多くのコンポーネントを含み、ユーザーがさまざまな構成を試行できるようにします。ただし、プロダクションでの運用時には、コレクターに必要なコンポーネントのみを含めることを推奨します。これには以下のいくつかの理由があります:
- コレクターのサイズを削減し、デプロイ時間を短縮する
- 利用可能な攻撃面を減少させ、コレクターのセキュリティを向上させる
カスタムコレクターは、OpenTelemetry Collector Builderを使用して構築できます。
OTelを使用したデータの取り込み
コレクターのデプロイ役割
ログを収集してClickHouseに挿入するために、OpenTelemetry Collectorの使用を推奨します。OpenTelemetry Collectorは、主に2つの役割でデプロイできます:
- エージェント - エージェントインスタンスは、サーバーやKubernetesノードなどのエッジでデータを収集するか、アプリケーションから直接イベントを受信します。後者の場合、エージェントインスタンスはアプリケーションと共に、または同じホスト上で実行されます(サイドカーやDaemonSetのように)。エージェントは、データを直接ClickHouseに送信するか、ゲートウェイインスタンスに送信することができます。前者の場合、これをエージェントデプロイパターンと呼びます。
- ゲートウェイ - ゲートウェイインスタンスは、スタンドアロンサービス(たとえば、Kubernetes内のデプロイメント)を提供し、通常はクラスターごと、データセンターごと、またはリージョンごとにデプロイされます。これらは、単一のOTLPエンドポイントを介してアプリケーション(または別のコレクターからのエージェント)のイベントを受信します。通常、一連のゲートウェイインスタンスがデプロイされ、負荷を分散するためにアウト・オブ・ザ・ボックスのロードバランサーが使用されます。すべてのエージェントとアプリケーションがこの単一のエンドポイントにシグナルを送信すると、これをゲートウェイデプロイパターンと呼ぶことがよくあります。
以下では、単純なエージェントコレクターがClickHouseに直接イベントを送信するものとします。ゲートウェイの使用と適用時期についての詳細はゲートウェイを使ったスケーリングを参照してください。
ログの収集
コレクターを使用する主な利点は、サービスがデータを迅速にオフロードできることです。コレクターは、リトライ、バッチ処理、暗号化、さらには機密データのフィルタリングなどの追加処理を行います。
コレクターは、受信者、プロセッサー、およびエクスポーターという3つの主要な処理段階のための用語を使用します。受信者はデータ収集に使用され、プルまたはプッシュベースのいずれかになります。プロセッサーはメッセージの変換や強化を実行する能力を提供します。エクスポーターは、データを下流サービスに送信する役割を担っています。このサービスは理論的には別のコレクターである可能性がありますが、以下の最初の議論では、すべてのデータが直接ClickHouseに送信されると仮定します。

ユーザーは、受信者、プロセッサー、およびエクスポーターの完全なセットに精通することを推奨します。
コレクターは、ログを収集するための2つの主要受信者を提供します:
OTLP経由 - この場合、ログはOTLPプロトコルを介してOpenTelemetry SDKからコレクターに直接(プッシュ)されます。OpenTelemetryデモは、このアプローチを採用しており、各言語のOTLPエクスポーターはローカルのコレクターエンドポイントを想定しています。この場合、コレクターはOTLP受信者で構成する必要があります。—上記のデモの設定を参照。このアプローチの利点は、ログデータに自動的にトレースIDが含まれ、ユーザーが特定のログのトレースやその逆を後で識別できることです。

このアプローチでは、ユーザーが適切な言語SDKでコードを計測する必要があります。
- Filelog受信者を介したスクレイピング - この受信者は、ディスク上のファイルをトレースし、ログメッセージを形成してClickHouseに送信します。この受信者は、マルチラインメッセージの検出、ログのロールオーバー、再起動時の堅牢性のためのチェックポイント、および構造の抽出などの複雑なタスクを処理します。この受信者は、DockerやKubernetesコンテナログをトレースすることもでき、helmチャートとしてデプロイ可能で、これらから構造を抽出し、ポッドの詳細で強化します。

ほとんどのデプロイメントは上記の受信者の組み合わせを使用します。ユーザーはコレクタードキュメントを読んで基本的な概念と設定構造およびインストール方法に精通することを推奨します。
構造化ログと非構造化ログ
ログは、構造化されている場合と非構造化されている場合があります。
構造化ログは、JSONのようなデータ形式を使用し、httpコードやソースIPアドレスのようなメタデータフィールドを定義します。
非構造化ログは、通常、正規表現パターンを介して抽出可能な固有の構造を持ちながら、ログを単に文字列として表現します。
ユーザーは、可能な限り構造化されたロギングを使用し、JSON(つまりndjson)でログを記録することを強く推奨します。これにより、ClickHouseに送信する前もしくは挿入時にコレクタープロセッサーを使用して、後でログの処理が簡素化されます。構造化ログは、後の処理リソースを節約し、ClickHouseソリューションで必要なCPUを削減します。
例
例の目的で、構造化(JSON)および非構造化のロギングデータセットを提供します。各データセットには約10m行が含まれています。以下のリンクから入手可能です:
以下の例では構造化データセットを使用します。このファイルをダウンロードして解凍して、以下の例を再現してください。
次の構成は、OTelコレクターがこれらのファイルをディスク上で読み取り、filelog受信者を使用し、結果として得られるメッセージをstdoutに出力するための簡単な設定を表しています。ログが構造化されているため、json_parser
オペレーターを使用します。access-structured.logファイルのパスを変更してください。
以下の例は、ログからタイムスタンプを抽出します。これには、json_parser
オペレーターを使用して、ログ行全体をJSON文字列に変換し、結果をLogAttributes
に配置する必要があります。これは計算コストが高く、ClickHouseでより効率的に行うことができます - SQLで構造を抽出する。当該s
の非構造化の例は、regex_parser
を使用して実現します。詳細はこちらで確認できます。
ユーザーは公式のインストール手順に従って、コレクターをローカルにインストールできます。重要なのは、contribディストリビューション(filelog
受信者を含む)を使用するように指示が変更されていることを確認することです。例えば、otelcol_0.102.1_darwin_arm64.tar.gz
の代わりに、ユーザーはotelcol-contrib_0.102.1_darwin_arm64.tar.gz
をダウンロードします。リリースはこちらで見つけることができます。
インストールが完了したら、OTelコレクターは以下のコマンドで実行できます:
構造化ログを使用している場合、メッセージは出力で以下のような形になります:
上記は、OTelコレクターによって生成された単一のログメッセージを表しています。これらのメッセージは、後のセクションでClickHouseに取り込むことになります。
ログメッセージの完全なスキーマと、他の受信者を使用している場合は存在する可能性のある追加のカラムは、こちらで維持されています。ユーザーはこのスキーマに慣れることを強く推奨します。
ここでの重要なポイントは、ログ行自体がBody
フィールド内の文字列として保持されている一方で、json_parser
のおかげでJSONがAttributesフィールドに自動的に抽出されていることです。同様に、このオペレーターは、適切なTimestamp
カラムにタイムスタンプを抽出するために使用されています。OTelを使用したログ処理の推奨事項については、処理を参照してください。
オペレーターは、ログ処理の最も基本的な単位です。各オペレーターは、ファイルから行を読み取ったり、フィールドからJSONを解析したりするなど、単一の責任を果たします。オペレーターは、パイプライン内で必要な結果を得るために連鎖させます。
上記のメッセージにはTraceID
またはSpanID
フィールドは含まれていません。これらは存在する可能性があり、たとえば、ユーザーが分散トレースを実装している場合は、上記の同じ技術を使用してJSONから抽出できます。
ローカルまたはKubernetesログファイルを収集する必要があるユーザーは、filelog受信者の利用可能な設定オプションや、オフセットおよび複数行のログパースがどのように処理されているかに慣れることをお勧めします。
Kubernetesログの収集
Kubernetesログの収集については、OpenTelemetryドキュメントガイドを推奨します。Kubernetes Attributes Processorは、ポッドメタデータでログやメトリクスを強化するために推奨されます。これにより、動的メタデータ(たとえば、ラベル)が作成され、ResourceAttributes
カラムに保存される可能性があります。ClickHouseは現在、このカラムにタイプMap(String, String)
を使用しています。マップの使用およびマップからの抽出についての詳細は、最適化や取り扱いに関するさらなる情報を参照してください。
トレースの収集
コードに計測を実装し、トレースを収集したいユーザーには、公式のOTelドキュメントに従うことを推奨します。
イベントをClickHouseに送信するには、ユーザーはOTelコレクターをデプロイし、適切な受信者を介してOTLPプロトコルでトレースイベントを受信する必要があります。OpenTelemetryデモは、各サポートされる言語を計測してコレクターに送信する例を提供します。以下に、stdoutにイベントを出力するための適切なコレクター構成の例を示します:
例
トレースはOTLPを介して受信する必要があるため、telemetrygen
ツールを使用してトレースデータを生成します。インストール手順はこちらを参照してください。
以下の構成は、OTLP受信者でトレースイベントを受信し、stdoutに送信します。
この構成は次のようにして実行します:
トレースイベントはtelemetrygen
を介してコレクターに送信されます:
これにより、以下のようなトレースメッセージがstdoutに出力されます:
上記は、OTelコレクターによって生成された単一のトレースメッセージを表しています。これらのメッセージは、後のセクションでClickHouseに取り込むことになります。
トレースメッセージの完全なスキーマはこちらで維持されています。ユーザーがこのスキーマにも精通することを強く推奨します。
処理 - フィルタリング、変換、および強化
ログイベントのタイムスタンプ設定の前の例で示したように、ユーザーは必然的にイベントメッセージをフィルタリング、変換、および強化したいと考えるでしょう。これは、OpenTelemetryの多くの機能を使用して実現できます。
-
プロセッサー - プロセッサーは、受信者によって収集されたデータを修正または変換し、エクスポーターに送信します。プロセッサーは、コレクターの構成の
processors
セクションに設定された順序で適用されます。これらはオプションですが、最小限のセットが一般に推奨されます。ClickHouseにOTelコレクターを使用する場合、プロセッサーは以下のように制限することを推奨します:- memory_limiterは、コレクターのメモリ不足の状況を防ぐために使用されます。リソースの見積もりに関する推奨事項を参照してください。
- コンテキストに基づいて強化を行うプロセッサー。たとえば、Kubernetes Attributes Processorは、k8sメタデータでスパン、メトリクス、ログリソース属性を自動的に設定することを許可します。
- トレースが必要な場合のテールまたはヘッドサンプリング。
- 基本的なフィルタリング - オペレーターを使用できない場合、不要なイベントをドロップします(以下を参照)。
- バッチ処理 - ClickHouseでデータをバッチで送信するために必須です。ClickHouseへのエクスポートを参照してください。
-
オペレーター - オペレーターは、受信者で利用可能な最も基本的な処理単位を提供します。基本的なパースがサポートされ、SeverityやTimestampなどのフィールドを設定できます。JSONおよび正規表現パースがサポートされており、イベントフィルタリングや基本的な変換も可能です。ここでイベントフィルタリングを行うことを推奨します。
ユーザーは、オペレーターや変換プロセッサーを用いた過度なイベント処理を避けることをお勧めします。これらは特にJSONパースにおいて相当なメモリおよびCPUオーバーヘッドを招く可能性があります。挿入時にClickHouseですべての処理を行うことができ、マテリアライズドビューとカラムにおいて例外もあります - 特に、k8sメタデータの追加などのコンテキスト認識の強化を除きます。詳細はSQLで構造を抽出するを参照してください。
OTelコレクターを使用して処理を行う際は、ゲートウェイインスタンスで変換を行い、エージェントインスタンスで行う作業を最小限に抑えることを推奨します。これは、サーバー上で実行されているエッジのエージェントが必要とするリソースを最小限に抑えます。通常、ユーザーは、不要なネットワーク使用量を最小限に抑えるためのフィルタリング(通信量削減)、オペレーターによるタイムスタンプ設定、およびエージェントでのコンテキストが必要な強化の処理を行います。たとえば、ゲートウェイインスタンスが異なるKubernetesクラスターに存在する場合、k8sの強化はエージェントで行う必要があります。
例
以下の構成は、非構造化ログファイルの収集を示しています。ログ行から構造を抽出するためのオペレーター(regex_parser
)を使用してイベントをフィルタリングし、イベントをバッチ処理しメモリ使用量を制限するためのプロセッサーを使用しています。
config-unstructured-logs-with-processor.yaml
ClickHouseへのエクスポート
エクスポータは、データを1つ以上のバックエンドまたは宛先に送信します。エクスポータは、プル型またはプッシュ型のいずれかです。ClickHouseにイベントを送信するためには、ユーザーはプッシュ型の ClickHouseエクスポータを使用する必要があります。
ClickHouseエクスポータは、コアディストリビューションではなく、OpenTelemetry Collector Contribの一部です。ユーザーは、contribディストリビューションを使用するか、独自のコレクタを構築することができます。
以下に完全な設定ファイルの例を示します。
以下の主要設定に注意してください:
- pipelines - 上記の設定は、ログとトレース用の受信者、プロセッサ、エクスポータで構成されたパイプラインの使用を強調しています。
- endpoint - ClickHouseとの通信は、
endpoint
パラメータを介して構成されます。接続文字列tcp://localhost:9000?dial_timeout=10s&compress=lz4&async_insert=1
はTCPを介って通信を行うことを意味します。ユーザーがトラフィックスイッチングの理由でHTTPを好む場合は、接続文字列をこちらの説明に従って修正してください。この接続文字列内にユーザー名とパスワードを指定できる詳細な接続情報はこちらに記載されています。
重要: 上記の接続文字列は、圧縮(lz4)および非同期挿入の両方を有効にします。両方を常に有効にすることをお勧めします。バッチ処理で非同期挿入に関する詳細を確認してください。古いバージョンのエクスポータではデフォルトで圧縮が有効にならないため、必ず指定する必要があります。
- ttl - ここでの値は、データが保持される期間を決定します。「データの管理」に関する詳細。これを時間単位(例:72h)で指定する必要があります。以下の例では、データが2019年のものであり、挿入されるとすぐにClickHouseによって削除されるため、TTLを無効にしています。
- traces_table_nameおよびlogs_table_name - ログおよびトレーステーブルの名前を決定します。
- create_schema - 起動時にテーブルがデフォルトスキーマで作成されるかどうかを決定します。開始のためにはデフォルトでtrueです。ユーザーはこれをfalseに設定し、自分のスキーマを定義する必要があります。
- database - ターゲットデータベース。
- retry_on_failure - 失敗したバッチを再試行するかどうかを決定する設定です。
- batch - バッチプロセッサは、イベントがバッチとして送信されることを保証します。5000の値と5秒のタイムアウトを持つことをお勧めします。これらのうちどちらかが最初に到達すると、バッチがエクスポータにフラッシュされます。これらの値を下げると、クエリの準備の早い低レイテンシパイプラインが得られますが、ClickHouseへの接続やバッチが増えることになります。非同期挿入を使用しない場合は推奨されません。多すぎるパーツの問題が発生する可能性があります。逆に、ユーザーが非同期挿入を使用している場合、クエリの準備のためのデータの可用性は非同期挿入の設定にも依存しますが、コネクタからのデータフラッシュは早くなります。バッチ処理で詳細を確認してください。
- sending_queue - 送信キューのサイズを制御します。キュー内の各項目はバッチを含みます。このキューが超過すると、ClickHouseに到達できないがイベントが到着し続ける場合、バッチが破棄されます。
ユーザーが構造化されたログファイルを抽出し、ローカルのClickHouseインスタンスが実行中(デフォルトの認証で)であると仮定すると、ユーザーは以下のコマンドでこの設定を実行できます。
このコレクタにトレースデータを送信するには、以下のコマンドをtelemetrygen
ツールを使用して実行します:
実行中に、簡単なクエリでログイベントが存在することを確認してください:
同様に、トレースイベントについては、ユーザーはotel_traces
テーブルを確認できます:
組み込みスキーマ
デフォルトでは、ClickHouseエクスポータは、ログとトレースの両方に対してターゲットログテーブルを作成します。これはcreate_schema
設定を介して無効にできます。さらに、ログテーブルとトレーステーブルの名前は、上記の設定に従ってデフォルトのotel_logs
とotel_traces
から変更できます。
以下のスキーマでは、TTLが72hとして有効であると仮定します。
ログのデフォルトスキーマは以下に示されています(otelcol-contrib v0.102.1
):
ここに示されているカラムは、こちらで文書化されたOTel公式仕様に対応しています。
このスキーマに関するいくつかの重要な注意点:
- デフォルトでは、テーブルは
PARTITION BY toDate(Timestamp)
によって日付でパーティション分けされています。これにより、期限切れのデータを効率的に削除できます。 - TTLは
TTL toDateTime(Timestamp) + toIntervalDay(3)
によって設定され、コレクタ設定で設定された値に対応します。ttl_only_drop_parts=1
は、すべての行が期限切れたときにのみ部分全体が削除されることを意味します。これは部分内の行を削除することよりも効率的であり、高価な削除を回避します。この設定は常に有効にすることをお勧めします。TTLによるデータ管理に関する詳細を参照してください。 - テーブルはクラシックな
MergeTree
エンジンを使用しています。これはログおよびトレースに推奨され、変更する必要はありません。 - テーブルは
ORDER BY (ServiceName, SeverityText, toUnixTimestamp(Timestamp), TraceId)
によって順序付けされています。これにより、クエリがServiceName
、SeverityText
、Timestamp
およびTraceId
に対するフィルタリングに最適化されます。リスト内の早いカラムは遅いカラムよりもフィルタリングが速くなります。例えば、ServiceName
によるフィルタリングはTraceId
によるフィルタリングよりもかなり速くなります。ユーザーは、期待されるアクセスパターンに応じてこの順序を変更する必要があります。プライマリーキーの選択を参照してください。 - 上記のスキーマはカラムに
ZSTD(1)
を適用しています。これはログのための最良の圧縮を提供します。ユーザーは、より良い圧縮を得るためにZSTD圧縮レベルを上げることもできますが、これは稀にしか有益ではありません。この値を上げることは挿入時により高いCPUオーバーヘッドをもたらします(圧縮時)、ただし、解除(およびクエリ)は比較的同じままとなります。こちらを参照して、さらに詳細を確認してください。Timestamp
には追加のデルタエンコーディングが適用され、ディスク上のサイズを削減します。 ResourceAttributes
、LogAttributes
、およびScopeAttributes
がマップとして定義されていることに注意してください。ユーザーは、これらの違いを理解する必要があります。これらのマップへのアクセス方法や、キーへのアクセスを最適化する方法については、マップの使用を参照してください。- その他のタイプも(例:
ServiceName
はLowCardinalityとして)最適化されています。Bodyは、例のログではJSONですが、文字列として保存されています。 - マップのキーと値、ならびにBodyカラムにはブームフィルタが適用されています。これにより、これらのカラムへのクエリ時間が改善されることが狙いですが、通常は必要ありません。セカンダリ/データスキッピングインデックスを参照してください。
これもまた、こちらで文書化されたOTel公式仕様に対応するカラムを持ちます。ここでのスキーマは、上記のログスキーマと多くの同じ設定を使用しており、スパンに特有の追加のリンクカラムを持っています。
ユーザーには、自動スキーマ作成を無効にし、手動でテーブルを作成することをお勧めします。これにより、プライマリおよびセカンダリキーを変更したり、クエリパフォーマンスを最適化するための追加のカラムを導入する機会が得られます。スキーマ設計に関する詳細を参照してください。
挿入の最適化
ClickHouseを介して観測データを挿入する際に高い挿入性能を得ながら強力な一貫性の保証を得るために、ユーザーは簡単なルールに従う必要があります。OTelコレクタの正しい設定で、以下のルールは簡単に実行できます。これにより、ClickHouseを初めて使用する際に発生する一般的な問題を回避できます。
バッチ処理
デフォルトでは、ClickHouseへの各挿入は、挿入からのデータを含むストレージのパートを即座に作成します。したがって、データを多く含む小さな挿入を送信することは、少ないデータを含む多数の挿入を送信するよりも、必要な書き込み数を減少させます。少なくとも1,000行のデータを持つかなり大きなバッチでデータを挿入することをお勧めします。さらに詳細はこちらを参照してください。
デフォルトでは、ClickHouseへの挿入は同期的で、同一であれば冪等性があります。マージツリーエンジンファミリーのテーブルでは、ClickHouseはデフォルトで自動的に挿入の重複排除を行います。これは、以下のようなケースで挿入が耐障害性を持つことを意味します:
- (1) データを受信しているノードに問題がある場合、挿入クエリはタイムアウト(またはより具体的なエラー)となり、確認を受け取りません。
- (2) データがノードに書き込まれましたが、ネットワーク接続の中断により確認を送信できない場合、送信者はタイムアウトまたはネットワークエラーを受け取ります。
コレクタの観点から、(1)および(2)は区別が難しい場合があります。しかし、いずれの場合も、認証されていない挿入はすぐに再試行できます。再試行された挿入クエリが同じ順序で同じデータを含んでいれば、ClickHouseは(認証されていない)元の挿入が成功している場合に再試行された挿入を自動的に無視します。
ユーザーには、上記の要件を満たすために、以前の設定で示したバッチプロセッサを使用することをお勧めします。これにより、挿入が一貫したバッチの行として送信されることが保証されます。コレクタに高いスループット(1秒あたりのイベント)が期待される場合、各挿入で少なくとも5,000イベントが送信できるなら、これは通常、パイプラインで必要な唯一のバッチ処理です。この場合、コレクタはバッチプロセッサのtimeout
が到達する前にバッチをフラッシュし、パイプラインのエンドツーエンドレイテンシを低く保ち、バッチが一貫したサイズになります。
非同期挿入を使用する
通常、ユーザーはコレクタのスループットが低いときに小さなバッチを送信せざるを得なく、なおかつ最低限のエンドツーエンドレイテンシ内にデータがClickHouseに到達することを期待しています。この場合、バッチプロセッサのtimeout
が切れると、小さなバッチが送信されます。これが問題を引き起こす可能性があり、非同期挿入が必要となる時点です。このケースは、エージェント役のコレクタがClickHouseに直接送信するように構成されている場合に一般的に発生します。ゲートウェイは集約装置として機能することで、この問題を軽減できます - ゲートウェイでのスケーリングを参照してください。
大きなバッチが保証できない場合、ユーザーは非同期挿入を使用してClickHouseにバッチ処理を委託できます。非同期挿入を使用すると、データは最初にバッファに挿入され、その後データベースストレージに書き込まれます。

非同期挿入が有効になると、ClickHouseは①挿入クエリを受け取ると、クエリのデータを②最初にメモリ内バッファに書き込みます。そして、③次のバッファフラッシュが発生すると、バッファのデータはソートされ、データベースストレージにパートとして書き込まれます。注意すべきは、データがデータベースストレージにフラッシュされる前は、クエリによって検索可能ではなくなるということです。バッファフラッシュは構成可能です。
コレクタの非同期挿入を有効にするには、接続文字列にasync_insert=1
を追加します。配信保証を得るためには、ユーザーにはwait_for_async_insert=1
(デフォルト)を使用することをお勧めします - 詳細はこちらを参照してください。
非同期挿入からのデータは、ClickHouseバッファがフラッシュされたときに挿入されます。これは、async_insert_max_data_size
を超えた場合や、最初のINSERTクエリからasync_insert_busy_timeout_ms
ミリ秒が経過した場合に発生します。async_insert_stale_timeout_ms
がゼロ以外の値に設定されている場合、データは最後のクエリからasync_insert_stale_timeout_ms milliseconds
後に挿入されます。ユーザーはこれらの設定を調整してパイプラインのエンドツーエンドレイテンシを制御できます。バッファフラッシュを調整するために使用できる設定の詳細はこちらに記載されています。一般的に、デフォルト設定が適切です。
エージェントの数が少なく、スループットが低いが厳格なエンドツーエンドレイテンシ要件がある場合、適応型非同期挿入が有用なことがあります。一般的に、これらはClickHouseで見られる高スループットの観測ユースケースには適用されません。
最後に、非同期挿入を使用する際のClickHouseへの同期挿入に関連する以前の重複排除動作はデフォルトで無効になっています。必要な場合は、async_insert_deduplicate
の設定を参照してください。
この機能の構成に関する詳細はこちらで確認できます。詳細についてはこちらをご覧ください。
デプロイメントアーキテクチャ
OTelコレクタを使用してClickHouseを利用する際に、いくつかのデプロイメントアーキテクチャが可能です。それぞれの適用シーンを以下に説明します。
エージェントのみ
エージェントのみのアーキテクチャでは、ユーザーはOTelコレクタをエッジにエージェントとしてデプロイします。これらはローカルアプリケーションからトレースを受け取り(例:サイドカーコンテナとして)、サーバーやKubernetesノードからログを収集します。このモードでは、エージェントはデータをClickHouseに直接送信します。

このアーキテクチャは、小規模から中規模のデプロイメントに適しています。その主な利点は、追加のハードウェアが必要なく、ClickHouseの観測ソリューションの全体的なリソースフットプリントを最小限に抑え、アプリケーションとコレクタ間の単純なマッピングを維持できることです。
エージェントの数が数百を超えると、ユーザーはゲートウェイベースのアーキテクチャへの移行を検討すべきです。このアーキテクチャにはスケーリングに関していくつかの欠点があるため、次のように困難になります。
- 接続スケーリング - 各エージェントはClickHouseに接続を確立します。ClickHouseは数百(場合によっては数千)の同時挿入接続を維持することができますが、最終的にはこれが制限要因となり、挿入の効率が低下します。つまり、接続を維持するためにClickHouseがより多くのリソースを使用することになります。ゲートウェイを使用すると、接続の数を最小限に抑え、挿入をより効率的にします。
- エッジでの処理 - このアーキテクチャでは、すべての変換やイベント処理をエッジまたはClickHouseで行う必要があります。これは制限的であり、複雑なClickHouseのマテリアライズドビューまたは重要なサービスに影響を与える可能性のあるエッジでの重要な計算を推し進めることにつながる場合があります。
- 小さなバッチとレイテンシ - エージェントコレクタは非常に少ないイベントを個別に収集する場合が多くなります。通常、このことは、配信SLAを満たすために設定間隔でフラッシュするように設定する必要があります。これにより、コレクタはClickHouseに小さなバッチを送信することになります。これは不利ですが、非同期挿入を使用することで軽減できます - 挿入の最適化を参照してください。
clickhouse-gateway-config.yaml
これらの構成は、次のコマンドを使用して実行できます。
このアーキテクチャの主な欠点は、コレクタのセットを管理するためのコストとオーバーヘッドが発生することです。
より大規模なゲートウェイ中心のアーキテクチャを管理する例と学びに関連する例については、このブログ投稿を推奨します。
Kafkaの追加
読者は、上記のアーキテクチャではKafkaがメッセージキューとして使用されていないことに気付くかもしれません。
メッセージバッファとしてKafkaキューを使用することは、ロギングアーキテクチャで見られる一般的なデザインパターンであり、ELKスタックによって普及しました。これにはいくつかの利点があります。主に、メッセージ配信の保証を強化し、バックプレッシャーに対処するのに役立ちます。メッセージはコレクションエージェントからKafkaに送信され、ディスクに書き込まれます。理論的には、クラスタ化されたKafkaインスタンスは高スループットのメッセージバッファを提供すべきであり、データを線形にディスクに書き込む際の計算オーバーヘッドが少ないため、メッセージの解析と処理にかかるよりもはるかに効率的です。たとえば、Elasticでは、トークン化とインデックス作成のためにかなりのオーバーヘッドが発生します。エージェントからデータを移動することで、ソースでのログローテーションの結果としてメッセージが失われるリスクを減らすことができます。最後に、メッセージリプレイとクロスリージョンレプリケーションの機能を提供しており、特定のユースケースにとって魅力的である可能性があります。
ただし、ClickHouseは非常に迅速にデータを挿入できるため、ミリオン行/秒を処理できます(中程度のハードウェアで)。ClickHouseからのバックプレッシャーはまれです。多くの場合、Kafkaキューを活用することは、より大きなアーキテクチャの複雑さとコストを意味します。ログには銀行トランザクションや他のミッションクリティカルなデータと同じ配信の保証が必要ないという原則を受け入れることができる場合、Kafkaの複雑さを避けることをお勧めします。
ただし、高い配信保証やデータのリプレイ機能(潜在的には複数のソースへの)を必要とする場合、Kafkaは有用なアーキテクチャの追加となる可能性があります。

この場合、OTelエージェントはKafkaエクスポータを通じてKafkaにデータを送信するように構成できます。ゲートウェイインスタンスは、Kafkaレシーバーを使用してメッセージを消費します。詳細については、ConfluentおよびOTelドキュメントを参照することをお勧めします。
リソースの見積もり
OTelコレクタのリソース要件は、イベントスループット、メッセージのサイズ、実行される処理の量に依存します。OpenTelemetryプロジェクトは、ユーザーがリソース要件を見積もるために使用できるベンチマークを維持しています。
私たちの経験に基づくと、3コアと12GBのRAMを持つゲートウェイインスタンスは、毎秒約60,000イベントを処理できます。これは、フィールドをリネームする責任を持つ最小限の処理パイプラインが関与しており、正規表現は使用していないという前提です。
イベントをゲートウェイに送信する責任を持つエージェントインスタンスについては、ユーザーが予想する秒あたりのログに基づいてサイズ設定することをお勧めします。以下は、ユーザーが出発点として使用できるおおよその数値を示しています:
ロギングレート | コレクターエージェントへのリソース |
---|---|
1k/秒 | 0.2CPU, 0.2GiB |
5k/秒 | 0.5 CPU, 0.5GiB |
10k/秒 | 1 CPU, 1GiB |