メインコンテンツへスキップ
メインコンテンツへスキップ

OpenTelemetry による ClickHouse のトレーシング

OpenTelemetry は、分散アプリケーションからトレースとメトリクスを収集するためのオープンな標準仕様です。ClickHouse は OpenTelemetry を一部サポートしています。

ClickHouse へのトレースコンテキストの指定

ClickHouse は、W3C 勧告 で説明されているトレースコンテキスト HTTP ヘッダーを受け付けます。また、ClickHouse サーバー間やクライアントとサーバー間の通信に使用されるネイティブプロトコルを介して渡されるトレースコンテキストも受け付けます。手動でテストする場合、Trace Context 勧告に準拠したトレースコンテキストヘッダーは、clickhouse-client に対して --opentelemetry-traceparent および --opentelemetry-tracestate フラグを使用して指定できます。

親トレースコンテキストが指定されていない場合、または指定されたトレースコンテキストが上記の W3C 標準に準拠していない場合、ClickHouse は新しいトレースを開始します。その発生確率は、opentelemetry_start_trace_probability 設定で制御されます。

トレースコンテキストの伝播

トレースコンテキストは、次の場合に下流のサービスへ伝播されます。

  • Distributed テーブルエンジンを使用する場合など、リモートの ClickHouse サーバーに対してクエリを実行する場合。

  • url テーブル関数を使用する場合。この場合、トレースコンテキスト情報は HTTP ヘッダーで送信されます。

ClickHouse Keeper リクエストのトレース

ClickHouse は、ClickHouse Keeper リクエスト(ZooKeeper 互換のコーディネーションサービス)に対する OpenTelemetry によるトレーシングをサポートしています。この機能により、クライアントからのリクエスト送信からサーバー側での処理に至るまで、Keeper オペレーションのライフサイクル全体を詳細に可視化できます。

Keeper のトレーシングを有効化する

Keeper リクエストのトレーシングを有効化するには、ZooKeeper/Keeper クライアント設定で次の設定項目を設定します。

<clickhouse>
    <zookeeper>
        <node>
            <host>keeper1</host>
            <port>9181</port>
        </node>
        <!-- Enable OpenTelemetry tracing context propagation -->
        <pass_opentelemetry_tracing_context>true</pass_opentelemetry_tracing_context>
    </zookeeper>
</clickhouse>

Keeper のスパン種別

トレーシングが有効化されている場合、ClickHouse はクライアント側とサーバー側の Keeper 操作の両方に対してスパンを作成します。

クライアント側スパン:

  • zookeeper.create — 新しいノードを作成
  • zookeeper.get — ノードのデータを取得
  • zookeeper.set — ノードのデータを設定
  • zookeeper.remove — ノードを削除
  • zookeeper.list — 子ノードを一覧表示
  • zookeeper.exists — ノードの存在を確認
  • zookeeper.multi — 複数の操作をアトミックに実行
  • zookeeper.client.requests_queue — 送信前にリクエストがキューに滞留している時間

サーバー側スパン (Keeper):

  • keeper.receive_request — クライアントからのリクエストを受信して解析
  • keeper.dispatcher.requests_queue — ディスパッチャー内でのリクエストのキューイング
  • keeper.write.pre_commit — Raft コミット前の書き込みリクエストの前処理
  • keeper.write.commit — Raft コミット後の書き込みリクエストの処理
  • keeper.read.wait_for_write — 依存する書き込みを待機している読み取りリクエスト
  • keeper.read.process — 読み取りリクエストの処理
  • keeper.dispatcher.responses_queue — ディスパッチャー内でのレスポンスのキューイング
  • keeper.send_response — クライアントへのレスポンス送信

サンプリングとパフォーマンス

トレースのオーバーヘッドを抑えるために、Keeper は動的サンプリングを実装しています。サンプリングレートは、リクエストサイズに応じて自動的に 1/10,000 から 1/10 の範囲で調整されます。すべてのリクエスト(サンプリングされたもの/されていないものの両方)について、その処理時間がパフォーマンス監視用のヒストグラムメトリクスに記録されます。

ClickHouse 自体のトレース

ClickHouse は、各クエリおよびクエリ計画や分散クエリなど一部のクエリ実行ステージごとに trace spans を作成します。

トレース情報を有用にするには、JaegerPrometheus など、OpenTelemetry をサポートするモニタリングシステムにエクスポートする必要があります。ClickHouse は特定のモニタリングシステムへの依存を避け、代わりにシステムテーブルを通じてのみトレースデータを提供します。標準で要求されている OpenTelemetry のトレーススパン情報は、system.opentelemetry_span_log テーブルに保存されます。

このテーブルを利用するには、サーバー設定で有効化されている必要があります。デフォルトの設定ファイル config.xml 内の opentelemetry_span_log 要素を参照してください。デフォルトでは有効になっています。

タグまたは属性は、キーと値を含む 2 つの並列配列として保存されます。これらを扱うには ARRAY JOIN を使用します。

Log-query-settings

log_query_settings 設定を有効にすると、クエリの実行中に行われたクエリ設定の変更内容をログとして記録できるようになります。有効化されている場合、クエリ設定に対して行われたあらゆる変更は OpenTelemetry のスパンログに記録されます。この機能は、本番環境においてクエリ性能に影響を与えうる設定変更を追跡するのに特に有用です。

監視システムとの統合

現時点では、ClickHouse から監視システムへトレースデータをエクスポートするための既製ツールは用意されていません。

テスト用途として、system.opentelemetry_span_log テーブルに対して URL エンジンを使用したマテリアライズドビューをセットアップすることで、受信したログデータをトレースコレクターの HTTP エンドポイントに送信できます。例えば、http://localhost:9411 で稼働している Zipkin インスタンスに、Zipkin v2 の JSON フォーマットで最小限の span データを送信するには、次のようにします。

CREATE MATERIALIZED VIEW default.zipkin_spans
ENGINE = URL('http://127.0.0.1:9411/api/v2/spans', 'JSONEachRow')
SETTINGS output_format_json_named_tuples_as_objects = 1,
    output_format_json_array_of_rows = 1 AS
SELECT
    lower(hex(trace_id)) AS traceId,
    CASE WHEN parent_span_id = 0 THEN '' ELSE lower(hex(parent_span_id)) END AS parentId,
    lower(hex(span_id)) AS id,
    operation_name AS name,
    start_time_us AS timestamp,
    finish_time_us - start_time_us AS duration,
    cast(tuple('clickhouse'), 'Tuple(serviceName text)') AS localEndpoint,
    cast(tuple(
        attribute.values[indexOf(attribute.names, 'db.statement')]),
        'Tuple("db.statement" text)') AS tags
FROM system.opentelemetry_span_log

エラーが発生した場合、そのエラーが発生した対象のログデータの一部は、エラーを通知することなく失われます。データが届かない場合は、サーバーログでエラーメッセージを確認してください。