ストーリー
高橋アーキテクトがJaegerのUIを開いた。ウォーターフォールチャートにリクエストの流れが美しく表示されている。
Jaegerとは
Jaegerは、Uber社が開発した分散トレーシングのバックエンドです。CNCFのGraduatedプロジェクトとして、広く利用されています。
┌────────────────────────────────────────┐
│ Jaeger Architecture │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Collector │←─│ Agent │←─ App │
│ │ │ │(Sidecar) │ │
│ └────┬─────┘ └──────────┘ │
│ │ │
│ ┌────▼─────┐ │
│ │ Storage │ (Elasticsearch/Cassandra)│
│ └────┬─────┘ │
│ │ │
│ ┌────▼─────┐ │
│ │ Query │ (API + UI) │
│ └──────────┘ │
└────────────────────────────────────────┘
Jaegerのセットアップ(Docker Compose)
# docker-compose.yml
version: '3.8'
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # UI
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
environment:
- COLLECTOR_OTLP_ENABLED=true
app:
build: .
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318
- OTEL_SERVICE_NAME=order-service
depends_on:
- jaeger
アプリケーション側の設定
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Resource } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
const sdk = new NodeSDK({
resource: new Resource({
[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || 'my-service',
}),
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT + '/v1/traces',
}),
instrumentations: [
getNodeAutoInstrumentations({
'@opentelemetry/instrumentation-http': { enabled: true },
'@opentelemetry/instrumentation-express': { enabled: true },
'@opentelemetry/instrumentation-pg': { enabled: true },
}),
],
});
sdk.start();
Jaeger UIの使い方
1. トレース検索
検索条件:
- Service: order-service
- Operation: POST /api/orders
- Tags: error=true(エラーのみ)
- Min Duration: 2s(2秒以上のリクエスト)
- Lookback: Last 1 Hour
結果:
TraceID: abc123 | 12 Spans | 3.5s | order-service, payment-service, ...
TraceID: def456 | 8 Spans | 2.1s | order-service, inventory-service, ...
2. ウォーターフォールビュー
Trace: abc123 (Total: 3.5s)
order-service: POST /api/orders ━━━━━━━━━━━━━━━━━━━━━━━━━━ 3500ms
│
├─ auth-service: validateToken ━━━ 30ms
│
├─ order-service: db.query ━━ 15ms
│ └─ attributes: { db.statement: "INSERT INTO orders..." }
│
├─ inventory-service: checkStock ━━━━━ 50ms
│ └─ inventory-service: db.query ━━ 20ms
│
├─ payment-service: charge ━━━━━━━━━━━━━━━━━━━━━━ 3200ms ⚠️
│ ├─ payment-service: validate ━━ 10ms
│ └─ payment-service: stripe ━━━━━━━━━━━━━━━━━━━━ 3150ms ⚠️
│ └─ attributes: { http.url: "https://api.stripe.com/charges" }
│ └─ events: [{ name: "retry", attempt: 3 }]
│
└─ notification-service: send ━━━ 20ms
3. トレースの比較
Jaegerでは2つのトレースを並べて比較できます。正常なリクエストと異常なリクエストを比較することで、問題箇所を特定します。
Zipkinとの比較
| 項目 | Jaeger | Zipkin |
|---|---|---|
| 開発元 | Uber(現CNCF) | |
| 言語 | Go | Java |
| ストレージ | Elasticsearch, Cassandra, Kafka | Elasticsearch, MySQL, Cassandra |
| UI | 高機能(比較、DAG等) | シンプルで直感的 |
| OpenTelemetry対応 | ネイティブ対応 | エクスポーター経由 |
| 適したケース | 大規模、高度な分析 | 小〜中規模、シンプルな運用 |
トレースデータの分析パターン
// パターン1: 遅いリクエストの特定
// Jaeger UIで Duration > 2s のトレースをフィルタ
// パターン2: エラートレースの分析
// Tags: error=true でフィルタし、エラーSpanの属性を確認
// パターン3: 特定ユーザーのリクエスト追跡
// Tags: user.id=USR-042 でフィルタ
// パターン4: サービス間の依存関係
// DAG (Directed Acyclic Graph) ビューでサービスマップを確認
// パターン5: 統計的分析
// 同じOperationのトレースを集計し、P50/P95/P99を比較
ストレージの設計
// トレースの保持期間設計
interface TraceRetention {
hotStorage: {
backend: 'Elasticsearch';
retention: '7日';
purpose: '直近のトレースを高速検索';
};
coldStorage: {
backend: 'S3';
retention: '30日';
purpose: '過去のトレースをアーカイブ';
};
samplingRate: {
errors: 1.0; // エラーは100%保存
slowRequests: 1.0; // 2秒以上は100%保存
normal: 0.05; // 通常は5%保存
};
}
まとめ
| ポイント | 内容 |
|---|---|
| Jaeger | CNCFの分散トレーシングバックエンド |
| セットアップ | Docker Compose + OTel SDKで簡単に導入 |
| UIの活用 | ウォーターフォール、比較、DAGビュー |
| ストレージ | ホット/コールドの階層設計 + サンプリング |
チェックリスト
- Jaegerのアーキテクチャと構成を理解した
- Docker ComposeでJaegerをセットアップできる
- Jaeger UIでトレースを検索・分析できる
- Jaegerのストレージと保持期間を設計できる
次のステップへ
次は「サービス依存関係の可視化」を学びます。トレースデータからサービスマップを生成し、システム全体の構造を把握する方法を見ていきましょう。
推定読了時間: 40分