計測の技術
「計測できないものは改善できない」。パフォーマンス改善の基礎となる計測の技術を学びます。
計測の3本柱
┌─────────────────────────────────────────────────────────────┐
│ メトリクス、ログ、トレース │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ メトリクス (Metrics) │ │
│ │ ├── 数値データの時系列 │ │
│ │ ├── 例: CPU使用率、リクエスト数、レイテンシ │ │
│ │ └── ダッシュボードで可視化、アラート設定 │ │
│ │ │ │
│ │ ログ (Logs) │ │
│ │ ├── イベントの記録 │ │
│ │ ├── 例: エラーログ、アクセスログ │ │
│ │ └── 検索・分析で詳細調査 │ │
│ │ │ │
│ │ トレース (Traces) │ │
│ │ ├── リクエストの流れを追跡 │ │
│ │ ├── 例: サービス間の呼び出し関係 │ │
│ │ └── ボトルネックの特定 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3つを組み合わせて使う: │
│ メトリクスで異常検知 → ログで詳細確認 → トレースで追跡 │
│ │
└─────────────────────────────────────────────────────────────┘
メトリクス
メトリクスの種類
┌─────────────────────────────────────────────────────────────┐
│ メトリクスの4タイプ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Counter(カウンター): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 累積値、増加のみ │ │
│ │ 例: 総リクエスト数、総エラー数 │ │
│ │ 使い方: 差分を取ってレートを計算 │ │
│ │ rate(http_requests_total[5m]) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Gauge(ゲージ): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 現在値、増減する │ │
│ │ 例: CPU使用率、メモリ使用量、接続数 │ │
│ │ 使い方: そのまま使用 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Histogram(ヒストグラム): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 値の分布 │ │
│ │ 例: レイテンシの分布 │ │
│ │ 使い方: パーセンタイル計算 │ │
│ │ histogram_quantile(0.99, rate(http_duration[5m])) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Summary(サマリー): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ クライアント側でパーセンタイル計算 │ │
│ │ 例: P50, P90, P99のレイテンシ │ │
│ │ 使い方: そのまま使用(集計不可) │ │
│ └──────────────────────────────────────── ─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
重要なメトリクス
┌─────────────────────────────────────────────────────────────┐
│ 監視すべきメトリクス │
├─────────────────────────────────────────────────────────────┤
│ │
│ アプリケーション: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・リクエストレート(req/sec) │ │
│ │ ・レイテンシ(P50, P95, P99) │ │
│ │ ・エラーレート(%) │ │
│ │ ・アクティブスレッド数 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ JVM: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・ヒープ使用量(used / max) │ │
│ │ ・GC回数と時間 │ │
│ │ ・スレッド数 │ │
│ │ ・クラスロード数 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ データベース: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・接続プール使用率 │ │
│ │ ・クエリ実行時間 │ │
│ │ ・アクティブ接続数 │ │
│ │ ・待ち接続数 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ OS: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・CPU使用率 │ │
│ │ ・メモリ使用率 │ │
│ │ ・ディスクI/O │ │
│ │ ・ネットワークI/O │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
分散トレーシング
┌─────────────────────────────────────────────────────────────┐
│ リクエストの流れを追跡する │
├─────────────────────────────────────────────────────────────┤
│ │
│ マイクロサービスでは1つのリクエストが複数サービスを通る │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Client → API Gateway → Auth Service │ │
│ │ ↓ │ │
│ │ User Service → DB │ │
│ │ ↓ │ │
│ │ Cache Service │ │
│ │ ↓ │ │
│ │ Response │ │
│ │ │ │
│ │ どこで時間がかかった? │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ トレースで可視化: │
│ ┌──────────────────────── ─────────────────────────────┐ │
│ │ │ │
│ │ [Trace ID: abc123] │ │
│ │ ├── API Gateway [0ms - 5ms] 5ms │ │
│ │ ├── Auth Service [5ms - 15ms] 10ms │ │
│ │ ├── User Service [15ms - 85ms] 70ms ← 遅い │ │
│ │ │ └── DB Query [20ms - 80ms] 60ms │ │
│ │ └── Cache Service [85ms - 90ms] 5ms │ │
│ │ │ │
│ │ Total: 90ms │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
トレースの構成要素
┌─────────────────────────────────────────────────────────────┐
│ Trace, Span, Context │
├─────────────────────────────────────────────────────────────┤
│ │
│ Trace(トレース): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1つのリクエスト全体を表す │ │
│ │ 一意のTrace IDを持つ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Span(スパン): │
│ ┌────────────────────────────────── ───────────────────┐ │
│ │ トレース内の1つの処理単位 │ │
│ │ 開始時刻、終了時刻、タグ、ログを持つ │ │
│ │ 親子関係を持つ(ツリー構造) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Context(コンテキスト): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ サービス間でTrace IDを伝播する仕組み │ │
│ │ HTTPヘッダー(traceparent等)で渡す │ │
│ └─────────────────────────────────────────────── ──────┘ │
│ │
│ 主要なツール: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・Jaeger │ │
│ │ ・Zipkin │ │
│ │ ・AWS X-Ray │ │
│ │ ・Datadog APM │ │
│ │ ・OpenTelemetry(標準仕様) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────── ─────────────────────────────────┘
プロファイリング
┌─────────────────────────────────────────────────────────────┐
│ コードレベルでボトルネックを特定 │
├────────────────────────────────────────────────────── ───────┤
│ │
│ CPUプロファイリング: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ どのメソッドがCPU時間を消費しているか │ │
│ │ │ │
│ │ 例(Flame Graph): │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ main() │ │ │
│ │ │ ┌───────────────────────────────────┬─────┐ │ │ │
│ │ │ │ processRequest() 60% │other│ │ │ │
│ │ │ │ ┌─────────────────────┬─────────┐│ │ │ │ │
│ │ │ │ │ parseJson() 40% │validate││ │ │ │ │
│ │ │ └─┴─────────────────────┴─────────┴┴─────┘ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ parseJson()が40%のCPU時間を使用 → 最適化候補 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ メモリプロファイリング: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ どのオブジェクトがメモリを消費しているか │ │
│ │ どこでオブジェクトが生成されているか │ │
│ │ メモリリークの原因特定 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Javaのツール: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・async-profiler(低オーバーヘッド) │ │
│ │ ・JDK Flight Recorder (JFR) │ │
│ │ ・VisualVM │ │
│ │ ・YourKit、JProfiler(商用) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
計測の設計
┌────────────────── ───────────────────────────────────────────┐
│ 何を計測するか設計する │
├─────────────────────────────────────────────────────────────┤
│ │
│ SLI(Service Level Indicator): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ サービスの品質を測る指標 │ │
│ │ 例: レイテンシP99、可用性、エラーレート │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ SLO(Service Level Objective): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SLIの目標値 │ │
│ │ 例: P99レイテンシ < 200ms、可用性 > 99.9% │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ SLA(Service Level Agreement): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SLOを守れなかった場合の契約(ペナルティ等) │ │
│ │ SLOより緩く設定することが多い │ │
│ └─────────────────── ──────────────────────────────────┘ │
│ │
│ 計測設計のポイント: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. ユーザー視点の指標を選ぶ │ │
│ │ 2. 測定可能な形で定義する │ │
│ │ 3. アラートと連動させる │ │
│ │ 4. 継続的に見直す │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
まとめ
┌─────────────────────────────────────────────────────────────┐
│ 計測の心得 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 3本柱を使い分ける: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ メトリクス: 全体像の把握、アラート │ │
│ │ ログ: 詳細な調査、デバッグ │ │
│ │ トレース: リクエストの流れ、ボトルネック特定 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 計測のオーバーヘッドに注意: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・計測自体がパフォーマンスに影響することがある │ │
│ │ ・本番では軽量な計測、開発では詳細な計測 │ │
│ │ ・サンプリングの活用 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 最初から入れておく: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・問題が起きてから入れるのでは遅い │ │
│ │ ・フレームワークの計測機能を活用 │ │
│ │ ・Spring Boot Actuator、Micrometer等 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘