メインコンテンツまでスキップ

分散トレーシング

このドキュメントの目的

分散トレーシングの基本概念を理解し、マイクロサービス環境でのリクエスト追跡がなぜ必要なのかを把握することが目標です。トレース・スパン・コンテキスト伝播の仕組みを学び、サンプリング戦略の選択基準を理解します。

IDサービスを題材にした具体例を使用しますが、設計原則自体はあらゆるSaaSに共通して適用できます。


なぜ分散トレーシングが必要か

モノリスとマイクロサービスの違い

モノリスでのデバッグ:

┌────────────────────────────────────┐
│ モノリスアプリケーション │
│ │
│ リクエスト → 認証 → DB → レスポンス │
│ │
│ → スタックトレースで全処理が見える │
│ → ログも1つのプロセス内で完結 │
└────────────────────────────────────┘
マイクロサービスでのデバッグ:

クライアント


┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│API │───▶│認証 │───▶│ユーザー │───▶│通知 │
│Gateway │ │サービス │ │サービス │ │サービス │
└────────┘ └────────┘ └────────┘ └────────┘
│ │ │ │
▼ ▼ ▼ ▼
ログA ログB ログC ログD

→ 「どのログが同じリクエストに属するか」が分からない
→ 「どのサービスで遅延が発生しているか」が見えない
→ 「エラーの原因がどのサービスにあるか」が特定困難

分散トレーシングが解決する課題

課題従来のアプローチ分散トレーシングによる解決
リクエストの追跡ログをgrepしてリクエストIDで突合トレースIDで全サービスのスパンを一覧
レイテンシの特定各サービスのログのタイムスタンプを比較ウォーターフォール図で即座に確認
エラーの原因特定各サービスのエラーログを個別に調査エラースパンから根本原因を直接特定
サービス間の依存関係ドキュメントや設計図に依存トレースデータからサービスマップを自動生成

トレース・スパン・コンテキスト

基本概念

トレースの構造:

Trace(トレース): 1つのリクエストの全体を表す
┌──────────────────────────────────────────────────────────┐
│ Trace ID: 4bf92f3577b34da6a3ce929d0e0e4736 │
│ │
│ Span A: POST /authorize (API Gateway) │
│ ├── Span B: validateClient (認証サービス) │
│ │ └── Span C: SELECT client (DB) │
│ ├── Span D: checkConsent (認可サービス) │
│ │ └── Span E: SELECT consent (DB) │
│ └── Span F: generateCode (認可サービス) │
│ └── Span G: INSERT auth_code (DB) │
└──────────────────────────────────────────────────────────┘

スパンの構成要素

スパンのデータ構造:

┌──────────────────────────────────────────────────┐
│ Span │
│ │
│ trace_id: 4bf92f3577b34da6a3ce929d0e0e4736 │
│ span_id: 00f067aa0ba902b7 │
│ parent_id: a3ce929d0e0e4736 (なければRoot) │
│ operation: "POST /authorize" │
│ service: "idp-server" │
│ start_time: 2026-03-04T10:23:45.123Z │
│ duration: 320ms │
│ status: OK │
│ │
│ attributes: │
│ http.method: POST │
│ http.url: /authorize │
│ http.status_code: 302 │
│ tenant_id: tenant-a │
│ client_id: app-1 │
│ │
│ events: │
│ - "consent check passed" (t+50ms) │
│ - "authorization code generated" (t+280ms) │
└──────────────────────────────────────────────────┘
要素説明用途
trace_idトレース全体の一意識別子同一リクエストの全スパンを関連付け
span_idスパンの一意識別子個々の処理単位を識別
parent_id親スパンのIDスパン間の親子関係を表現
operation処理名何をしているかを示す
attributesキーバリューペアコンテキスト情報の付与
eventsタイムスタンプ付きイベントスパン内の重要なポイントを記録

コンテキスト伝播

コンテキスト伝播の仕組み

コンテキスト伝播の流れ:

サービスA サービスB
┌─────────────────────┐ ┌─────────────────────┐
│ Span A を作成 │ │ │
│ │ │ │
│ HTTPリクエスト送信: │───▶│ ヘッダーからコンテキ │
│ traceparent: │ │ ストを抽出 │
│ 00-{trace_id}- │ │ │
│ {span_id}-01 │ │ Span B を作成 │
│ │ │ (parent = Span A) │
└─────────────────────┘ └─────────────────────┘

┌─────────────────────────────────────────────────┐
│ HTTPヘッダーの例: │
│ │
│ traceparent: 00-4bf92f3577b34da6a3ce929d0e0e │
│ 4736-00f067aa0ba902b7-01 │
│ ── ──────────────── ────────── │
│ ver trace_id span_id │
│ │
│ tracestate: vendor1=value1,vendor2=value2 │
│ (ベンダー固有の追加情報) │
└─────────────────────────────────────────────────┘

伝播フォーマットの比較

フォーマット標準化ヘッダー名推奨度
W3C Trace ContextW3C標準traceparent, tracestate推奨
B3 (Zipkin)事実上の標準X-B3-TraceId, X-B3-SpanId, X-B3-Sampledレガシー互換
B3 SingleB3の単一ヘッダー版b3レガシー互換
JaegerJaeger固有uber-trace-idJaeger環境のみ

推奨: 新規システムではW3C Trace Contextを採用します。OpenTelemetryのデフォルトであり、業界標準として広く採用されています。

IDサービスでのコンテキスト伝播例

認可コードフローでのトレース伝播:

ブラウザ IDサービス 外部IdP
┌────────┐ ┌────────────┐ ┌────────┐
│ │ GET │ │ │ │
│ │ /authorize │ Span A │ │ │
│ │─────────────▶│ 認可リクエ │ │ │
│ │ │ スト処理 │ │ │
│ │ │ │ │ │
│ │ │ Span B │ │ │
│ │ │ クライアン │ │ │
│ │ │ ト検証 │ │ │
│ │ │ │ Span C │ │
│ │ │ 外部IdP ──│─────────▶│ 認証 │
│ │ │ 連携 │traceparent│ │
│ │ │ │◀─────────│ │
│ │ │ Span D │ │ │
│ │ │ 認可コード │ │ │
│ │ 302 │ 生成 │ │ │
│ │◀─────────────│ │ │ │
└────────┘ └────────────┘ └────────┘

結果のトレース:
├─ Span A: POST /authorize ──────────── 500ms
│ ├─ Span B: validateClient ────────── 20ms
│ ├─ Span C: federateWithIdP ──────── 350ms ← ボトルネック
│ └─ Span D: generateAuthCode ──────── 30ms

サンプリング戦略

なぜサンプリングが必要か

全リクエストのトレースを記録すると、ストレージコストとネットワーク負荷が膨大になります。

サンプリングの必要性:

1000 req/s × 1トレース平均5スパン × 1スパン500B
= 2.5 MB/s = 216 GB/日

→ 全量記録はコスト的に現実的でない
→ サンプリングでバランスを取る

Head-based サンプリング

Head-based サンプリング:

リクエスト到着時に「記録するか」を決定

┌──────────┐
│ リクエスト │
│ 到着 │
└────┬─────┘


┌──────────┐ Yes (10%) ┌──────────┐
│ サンプリ │──────────────────▶│ 全スパン │
│ ング判定 │ │ を記録 │
└────┬─────┘ └──────────┘

│ No (90%)

┌──────────┐
│ トレース │
│ を破棄 │
└──────────┘

メリット: シンプル、低オーバーヘッド
デメリット: エラーリクエストも90%破棄される

Tail-based サンプリング

Tail-based サンプリング:

リクエスト完了後に「記録するか」を決定

┌──────────┐
│ 全スパン │
│ を一時的に│
│ バッファ │
└────┬─────┘


┌──────────┐ エラー / 高レイテンシ ┌──────────┐
│ 条件判定 │──────────────────────────▶│ 保存 │
│ (完了後) │ │ (100%) │
└────┬─────┘ └──────────┘

│ 正常 / 低レイテンシ

┌──────────┐ サンプリング (10%) ┌──────────┐
│ 通常の │──────────────────────────▶│ 保存 │
│ サンプリ │ └──────────┘
│ ング判定 │
└────┬─────┘
│ (90%)

┌──────────┐
│ 破棄 │
└──────────┘

メリット: エラーや遅延リクエストを確実に記録
デメリット: コレクターにバッファが必要、複雑

サンプリング戦略の比較

観点Head-basedTail-based
判定タイミングリクエスト到着時リクエスト完了後
エラーの捕捉サンプリング率に依存エラーは100%捕捉可能
実装の複雑さシンプルコレクターにバッファが必要
オーバーヘッド低い中〜高(一時バッファ)
コスト予測しやすいエラー頻度で変動
推奨シーントラフィックが多く、コストを抑えたいエラーや遅延の調査を重視

推奨サンプリング設計

段階的なサンプリング設計:

┌─────────────────────────────────────────────────┐
│ 優先度1: エラーリクエスト → 100% 記録 │
│ │
│ 優先度2: 高レイテンシリクエスト(p99超)→ 100% 記録│
│ │
│ 優先度3: 正常リクエスト → 1〜10% サンプリング │
└─────────────────────────────────────────────────┘

IDサービスでの例:
・認証エラー → 全トレース記録(原因調査に必要)
・レイテンシ > 1秒 → 全トレース記録(ボトルネック調査)
・正常な認証 → 5% サンプリング(傾向把握)

トレースの読み方

ウォーターフォール図

トレースのウォーターフォール表示:

時間 → 0ms 100ms 200ms 300ms 400ms 500ms
| | | | | |
Span A ──████████████████████████████████████████──── 500ms
(POST /authorize)
|
Span B ──████──────────────────────────────────────── 20ms
(validateClient)
|
Span C ──────────████████████████████████████──────── 350ms
(federateWithIdP) ← ボトルネック!
|
Span D ──────────────────────────────────────████──── 30ms
(generateAuthCode)

読み方:
・横幅 = 処理時間
・インデント = 親子関係
・赤色 = エラー
・最も幅が広いスパンがボトルネック候補

トレースからの調査パターン

調査パターン何を見るかIDサービスでの例
ボトルネック特定最もDurationが長いスパン外部IdP連携(350ms / 500ms = 70%)
エラーの根本原因エラーステータスのスパンとその属性DB接続エラー → コネクションプール枯渇
N+1問題同一操作の大量の子スパンユーザー属性取得のSELECTが100回実行
不要な直列処理並列化可能な直列スパン独立した検証処理が直列に実行

まとめ

概念ポイント
分散トレーシングの必要性マイクロサービスではログだけではリクエストの全体像を把握できない
トレース・スパントレースはリクエスト全体、スパンは個々の処理単位を表す
コンテキスト伝播W3C Trace Context(traceparent)が業界標準
サンプリングエラー/高レイテンシは100%記録、正常リクエストは1〜10%サンプリング
トレースの読み方ウォーターフォール図でボトルネック・エラー・N+1問題を特定

最終更新: 2026-03-04 対象: SaaSアプリケーション開発者、SRE