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

パフォーマンスの基礎

パフォーマンスを語るために必要な基本概念を学びます。


パフォーマンスとは何か

┌─────────────────────────────────────────────────────────────┐
│ 「速い」とは何か? │
├─────────────────────────────────────────────────────────────┤
│ │
│ 「このシステムは速いですか?」 │
│ │
│ この質問には答えられない。なぜなら: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・何を基準に「速い」? │ │
│ │ ・どの操作の話? │ │
│ │ ・どのくらいの負荷で? │ │
│ │ ・誰にとって速い?(ユーザー?システム?) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ パフォーマンスは「定量的な指標」で語る必要がある │
│ │
└─────────────────────────────────────────────────────────────┘

2つの基本指標

レイテンシ(Latency)

┌─────────────────────────────────────────────────────────────┐
│ レイテンシ = 1回の処理にかかる時間 │
├─────────────────────────────────────────────────────────────┤
│ │
│ リクエスト レスポンス │
│ │ ↑ │
│ │ ────────────────────────────────────→│ │
│ │ レイテンシ │ │
│ │ (例: 50ms) │ │
│ │
│ ユーザー視点: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 「ボタンを押してから結果が表示されるまでの時間」 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ レイテンシが重要な場面: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・ユーザーの体感速度 │ │
│ │ ・リアルタイム処理(ゲーム、金融取引) │ │
│ │ ・同期的な処理の連鎖 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

スループット(Throughput)

┌─────────────────────────────────────────────────────────────┐
│ スループット = 単位時間あたりの処理量 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1秒間に処理できるリクエスト数 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ req │ req │ req │ req │ req │ req │ req │ req │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ 1秒間 │ │
│ │ スループット: 8 req/sec │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ スループットが重要な場面: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・バッチ処理(大量データの処理) │ │
│ │ ・システム全体のキャパシティ計画 │ │
│ │ ・コスト効率(同じリソースで何件処理できるか) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

レイテンシとスループットの関係

┌─────────────────────────────────────────────────────────────┐
│ 両方を同時に改善するのは難しい │
├─────────────────────────────────────────────────────────────┤
│ │
│ トレードオフの例: │
│ │
│ バッチ処理 vs 即時処理: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 即時処理: レイテンシ低 ← → スループット低 │ │
│ │ バッチ: レイテンシ高 ← → スループット高 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 例: DBへの書き込み │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 即時: 1件ずつINSERT → 速いが効率悪い │ │
│ │ バッチ: 100件まとめてINSERT → 遅いが効率良い │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ どちらを優先するかは「要件」による │
│ │
└─────────────────────────────────────────────────────────────┘

パーセンタイル

平均値の罠

┌─────────────────────────────────────────────────────────────┐
│ 平均値だけでは不十分 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 10回のリクエストのレイテンシ: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 10ms, 12ms, 11ms, 10ms, 13ms, │ │
│ │ 11ms, 10ms, 12ms, 11ms, 500ms ← 1回だけ遅い │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 平均値: 60ms │
│ │
│ でも実際は: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・90%のリクエストは 10-13ms で完了 │ │
│ │ ・10%のリクエストが 500ms もかかっている │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 平均60msは実態を反映していない │
│ │
└─────────────────────────────────────────────────────────────┘

P50, P95, P99

┌─────────────────────────────────────────────────────────────┐
│ パーセンタイルで「分布」を見る │
├─────────────────────────────────────────────────────────────┤
│ │
│ P50(50パーセンタイル)= 中央値 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 全リクエストの50%がこの値以下 │ │
│ │ 「典型的なユーザー体験」を表す │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ P95(95パーセンタイル) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 全リクエストの95%がこの値以下 │ │
│ │ 「ほとんどのユーザー体験」を表す │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ P99(99パーセンタイル) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 全リクエストの99%がこの値以下 │ │
│ │ 「最悪に近いケース」を表す │ │
│ │ SLOでよく使われる │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 例: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ P50: 12ms ← 半分のリクエストは12ms以下 │ │
│ │ P95: 45ms ← 95%のリクエストは45ms以下 │ │
│ │ P99: 200ms ← 99%のリクエストは200ms以下 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

なぜP99が重要か

┌─────────────────────────────────────────────────────────────┐
│ P99は「テールレイテンシ」を表す │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1日100万リクエストのシステムで: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ P99 = 200ms の場合 │ │
│ │ → 1万リクエスト(1%)が200ms以上かかる │ │
│ │ → 1万人のユーザーが「遅い」と感じる │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ さらに、マイクロサービスでは: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1リクエストが5つのサービスを呼ぶ場合 │ │
│ │ │ │
│ │ 各サービスのP99: 50ms │ │
│ │ │ │
│ │ 全体のP99は 50ms × 5 = 250ms ではない! │ │
│ │ │ │
│ │ どれか1つでも遅いと全体が遅くなる │ │
│ │ → 実際はもっと悪化する │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

キャパシティと飽和

┌─────────────────────────────────────────────────────────────┐
│ 負荷が上がるとどうなるか │
├─────────────────────────────────────────────────────────────┤
│ │
│ レイテンシ │
│ ↑ │
│ │ / │
│ │ / │
│ │ / ← 飽和点 │
│ │ / (急激に悪化) │
│ │ ──────────────────/ │
│ │ ↑ 線形領域 │
│ └────────────────────────────────→ 負荷 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 線形領域: 負荷が増えてもレイテンシはほぼ一定 │ │
│ │ 飽和点以降: 負荷が増えるとレイテンシが急激に悪化 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ なぜ急激に悪化するか: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・リソース(CPU、メモリ、接続)が枯渇 │ │
│ │ ・キューが溜まり始める │ │
│ │ ・待ち時間が処理時間を上回る │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 重要: 飽和点の「手前」で運用する │
│ 通常は最大キャパシティの70-80%を目安に │
│ │
└─────────────────────────────────────────────────────────────┘

なぜ飽和するのか(メカニズム)

負荷テストでVUs(仮想ユーザー数)を増やすと、ある時点からレイテンシが急激に悪化します。このメカニズムをリトルの法則で理解できます。

リトルの法則: L = λ × W

  • L = システム内の同時処理数
  • λ = 到着率(req/sec)
  • W = レイテンシ(sec)
┌─────────────────────────────────────────────────────────────┐
│ VUs増加 → 飽和のメカニズム │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【正常時】VUs=50, レイテンシ=50ms │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 到着率: 約 1000 req/sec (50 VUs / 0.05sec) │ │
│ │ 同時処理数: 1000 × 0.05 = 50 │ │
│ │ → 接続プール(100)に余裕あり │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【飽和開始】VUs=200, レイテンシ=50ms想定 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 到着率: 約 4000 req/sec (200 VUs / 0.05sec) │ │
│ │ 同時処理数: 4000 × 0.05 = 200 │ │
│ │ → 接続プール(100)を超過!待ちが発生 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【悪循環】待ちが発生すると... │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ レイテンシ: 50ms → 200ms(待ち時間が加算) │ │
│ │ 同時処理数: 4000 × 0.2 = 800 ← さらに増加! │ │
│ │ → キューがさらに溜まり、レイテンシがさらに悪化 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

飽和の3つの原因:

原因説明兆候
リソース枯渇CPU、メモリ、接続プールが上限に達するCPU使用率100%、接続プールpending増加
キュー蓄積処理待ちのリクエストが溜まるスレッドプール待ち、DB接続待ち
悪循環待ち時間増加 → 同時処理数増加 → さらに待ちP99が急激に悪化、タイムアウト発生
┌─────────────────────────────────────────────────────────────┐
│ 飽和を防ぐには │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. リソース上限を把握する │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 接続プール: 20 → 最大 20 × (1/W) req/sec │ │
│ │ 例: 20接続、50ms/処理 → 最大 400 req/sec │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 2. ボトルネックを解消する │
│ ┌─────────────────────────────────────────────────┐ │
│ │ レイテンシWを下げる → 同じリソースで多く捌ける │ │
│ │ 50ms → 25ms なら、スループット2倍 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 3. 適切にスケールする │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 接続プール増加、サーバー追加(水平スケール) │ │
│ │ ただしボトルネックがあると効果は限定的 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

詳細は パフォーマンスの法則(発展) を参照


まとめ

┌─────────────────────────────────────────────────────────────┐
│ パフォーマンスの基礎 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基本指標: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ レイテンシ: 1回の処理時間(ユーザー体験) │ │
│ │ スループット: 単位時間の処理量(システム効率) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ パーセンタイル: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ P50: 典型的なケース │ │
│ │ P95: ほとんどのケース │ │
│ │ P99: 最悪に近いケース(SLOで重要) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 心得: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・「速い」は定量的に語る │ │
│ │ ・平均値より分布(パーセンタイル)を見る │ │
│ │ ・飽和点の手前で運用する │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

次のステップ