Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

ClickStack の属性における Map 型と JSON 型の使い分け

ClickStack のデフォルトスキーマでは、resource、scope、log、span の属性は Map(LowCardinality(String), String) カラムに保存されます。ClickHouse は厳密に型付けされた JSON もサポートしており、ClickStack では Map の代わりにこれを使用するためのベータサポートも提供されています。

一般的なオブザーバビリティのワークロードでは、デフォルトの Map ベースのスキーマをそのまま使用することを推奨します。 JSON 型は、属性キーの種類が少なく、かつ安定しているワークロードで評価したいユーザー向けに利用できますが、一般用途向けの推奨スキーマではありません。

Map が推奨されるデフォルトである理由

オブザーバビリティデータの大部分は、resource attributes、scope attributes、span 属性、log 属性のような attribute によって占められます。これらは通常、規模が大きく、カーディナリティが高く、高スループットで取り込まれます。こうした attribute にどのスキーマを選ぶかが、取り込みコストとストレージレイアウトを左右する最も重要な要因です。

Map(LowCardinality(String), String) は、キーと値を単一の構造として格納します。従来の Map の欠点は、1 つのキーを読み取るだけでも map カラム全体を読む必要があったことです。しかし、これはもう当てはまりません。現在の ClickHouse は bucketed map serialization をサポートしており、map を複数の bucket に分割することで、クエリは必要な bucket だけを読み取れます。さらに、map のキーと値に対する テキスト索引 を組み合わせることで、つまり ClickStack のデフォルトスキーマ が採用している構成により、新しいキーが増えても取り込み時の追加コストを発生させることなく、Map は読み取り時にも選択的かつ高速に動作します。

実際には、これは次のことを意味します。

  • キーが増えても取り込みコストは安定。 新しい attribute キーを追加しても、ディスク上のカラムレイアウトは変わらず、新たな column file も作成されません。取り込みコストはキーのカーディナリティではなく、データ量によって決まります。
  • メタデータの爆発的な増加を防げる。 ディスク上の column file の数は、一意な attribute キーの数に連動しません。
  • 索引を使った選択的なルックアップ。 map のキーと値に対するテキスト索引により、すべての行をスキャンしなくても point lookup を実行できます。
  • 高スループットでも予測可能な動作。 Map は、tracing や logs で一般的な、バースト的でスキーマレスな attribute 群を、キーごとのオーバーヘッドなしで処理できます。

デフォルトで JSON を使わないのはなぜか

JSON 型は、これとは異なるアプローチを取ります。挿入時に、ClickHouse は見つかった各パスごとに、強く型付けされた専用のサブカラムを動的に作成します。読み取り時には、要求されたサブカラムだけを読み込めばよく、型も保持され、クエリ時のキャストも不要なため、これは魅力的です。

ただし、そのしわ寄せは取り込み時に生じます。多数の動的サブカラムを作成して管理すると、書き込み時のオーバーヘッドとメタデータの複雑さが増します。オブザーバビリティのワークロードでは、属性セットが非常に大きかったり変動が激しかったりするうえ、取り込みスループットも高いのが一般的なため、このオーバーヘッドは無視できません。max_dynamic_paths 制限を使えば、追加のパスを共有カラムに退避させることで影響を抑えられますが、共有カラムへのアクセスは専用サブカラムより遅いため、そもそも JSON を使う動機だった読み取り時の利点が薄れてしまいます。

bucketed map シリアライゼーションによって Map の従来の読み取り時オーバーヘッドの大半が解消されたため、一般的なオブザーバビリティのワークロードでは、JSON の読み取り時の利点は、もはや取り込み時のコストを上回りません。

それでも JSON を検討すべき場合

JSON 型は、次の条件をすべて満たす場合に、妥当な選択肢となり得ます。

  • 属性のキーセットが小さく安定しており、何千もの一意なキーが存在せず、新しいキーが追加されることもまれである。
  • 取り込みスループットが、属性のカーディナリティに対して控えめである。
  • クエリ時にキャストせず、属性に厳密な型でアクセスしたい (数値は数値のまま、ブール値はブール値のまま) 。
  • ClickStack でベータ機能を運用し、インテグレーションが変更される可能性を受け入れられる。

これらの条件をすべて満たさない場合は、デフォルトの Map ベースのスキーマを引き続き使用してください。

ベータステータス

ベータ機能

ClickStack はバージョン 2.0.4 から JSON 型をベータサポートしています。

JSON サポートの有効化

デフォルトのMapベースのスキーマではなく JSON 型のスキーマを使用するには、以下の環境変数を設定します。

変数 設定先 用途
OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' OTel collector ClickHouse で JSON type を使用したスキーマを作成します。
BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true HyperDX (ClickStack UI) アプリケーション層で JSON 型のスキーマに対してクエリできるようにします。ClickStack Open Source のみ。

Managed ClickStack

Managed ClickStack で JSON サポートを有効にするには、collector を設定する前に support@clickhouse.com へお問い合わせください。この機能は、ClickHouse Cloud の ClickStack UI (HyperDX) でも有効にする必要があります。

collector で OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' を設定します。例:

docker run -e OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' -e CLICKHOUSE_ENDPOINT=${CLICKHOUSE_ENDPOINT} -e CLICKHOUSE_USER=default -e CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD} -p 8080:8080 -p 4317:4317 -p 4318:4318 clickhouse/clickstack-otel-collector:latest

オープンソースの ClickStack

collector を含むすべてのデプロイメントで OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' を設定し、HyperDX のアプリケーションレイヤーでは BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true を設定して、JSON 型のスキーマに対してクエリを実行できるようにします。

例:

docker run -e OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' -e OPAMP_SERVER_URL=${OPAMP_SERVER_URL} -e CLICKHOUSE_ENDPOINT=${CLICKHOUSE_ENDPOINT} -e CLICKHOUSE_USER=default -e CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD} -p 8080:8080 -p 4317:4317 -p 4318:4318 clickhouse/clickstack-otel-collector:latest

MapベースのスキーマからJSONへの移行

デフォルトのMapベースのスキーマ から移行するには、次の手順に従ってください。

OTel collector を停止する

既存のテーブル名を変更し、データソースを更新する

既存のテーブル名を変更し、HyperDX のデータソースを更新します。

たとえば、次のようにします。

RENAME TABLE otel_logs TO otel_logs_map;
RENAME TABLE otel_metrics TO otel_metrics_map;

OTel collector をデプロイする

OTEL_AGENT_FEATURE_GATE_ARG を設定して OTel collector をデプロイします。

JSONスキーマ対応を有効にして HyperDX コンテナーを再起動する

export BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true

新しいデータソースを作成する

JSONテーブルを参照する新しいデータソースを HyperDX で作成します。

既存データの移行 (任意)

古いデータを新しい JSON テーブルに移行するには:

INSERT INTO otel_logs SELECT * FROM otel_logs_map;
INSERT INTO otel_metrics SELECT * FROM otel_metrics_map;
Navigation