このページの目次
分散トレーシング
リクエストが10以上のマイクロサービスにまたがる場合、どこに時間がかかっているかをどうやって特定するか?分散トレーシングは、各リクエストに trace ID を割り当て、サービス間の呼び出し関係を context propagation を通じて span context(trace ID + parent span ID + サンプリングフラグ)として伝播させ、各ノードに散在する断片を結合して完全な呼び出しチェーンを構築します。サンプリング戦略はコスト管理の鍵となります:全量サンプリングは高コストすぎ、固定比率サンプリングはロングテールのエラーを見逃す可能性があり、tail-based サンプリングは処理完了後にどの trace を保持するかを決定します。
Dapper (Google 2010) → OpenTelemetry
Google の Dapper 論文はオープンソースエコシステムに影響を与えました:Zipkin (Twitter) → Jaeger (Uber) → OpenTracing + OpenCensus → OpenTelemetry (CNCF、現在の標準)。
Trace と Span
Context Propagation
サービス間での trace の伝播が重要である——各サービスは「自分がどの trace のどの span であるか」を把握していなければならない:
HTTP: traceparent: 00-<trace_id>-<span_id>-<trace_flags>
W3C Trace Context (標準): traceparent ヘッダー
gRPC: メタデータ (grpc-trace-bin)
Kafka: メッセージヘッダー
trace_flags: bit 0 = SAMPLED(サンプリング対象かどうか)、他の bits は予約済み。
内部実装: トレーサーは下流サービスへの呼び出し時に新しい span(呼び出し元 span の子)を作成し、trace_id + new_span_id を outbound ヘッダーに格納する。下流のミドルウェア/ライブラリ(HTTP クライアント、gRPC スタブ、DB ドライバー)は、レスポンス受信時に trace context を抽出し、自動的に子 span を作成する。
サンプリング
全量収集 → オーバーヘッドが許容できない(各 span につき約 1μs のオーバーヘッド + ネットワーク/ストレージコスト)。サンプリング戦略が必要:
- Head-based (確率的): trace 開始時にサンプリングするかどうかを決定する(ランダムで 1/100 または 1/1000)。単純だが、エラーを含む trace を見逃す可能性がある。
- Tail-based (インテリジェント): すべての span をキャッシュ(ローカルバッファ)し、trace 完了後に結果(ERROR? SLO を超えるレイテンシ?)に基づいて保持するかどうかを決定する。エラーを見逃さないが、メモリオーバーヘッドが大きい。OpenTelemetry の
tailsamplingプロセッサーがこの戦略を実装している。
Jaeger 展開 (参考)
# Agent (ホストごとに 1 つ、UDP を介してアプリから span を受信)
# Collector (セントラル、エージェントから受信 → ストレージに書き込み)
# Storage (Cassandra/Elasticsearch)
# Query (UI + API)
参考
- 論文: "Dapper, a Large-Scale Distributed Systems Tracing Infrastructure" (Google, 2010)
- OpenTelemetry: opentelemetry.io/docs/specs/otel/trace
- Jaeger: jaegertracing.io
Keywords: 分散トレーシング, Dapper, OpenTelemetry, Span, trace context propagation, W3C Trace Context, サンプリング