パフォーマンスの基礎
パフォーマンスを語るために必要な基本概念を学びます。
パフォーマンスとは何か
┌─────────────────────────────────────────────────── ──────────┐
│ 「速い」とは何か? │
├─────────────────────────────────────────────────────────────┤
│ │
│ 「このシステムは速いですか?」 │
│ │
│ この質問には答えられない。なぜなら: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・何を基準に「速い」? │ │
│ │ ・どの操作の話? │ │
│ │ ・どのくらいの負荷で? │ │
│ │ ・誰にとって速い?(ユーザー?システム?) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ パフォーマンスは「定量的な指標」で語る必要がある │
│ │
└─────────────────────────────────────────────────────────────┘
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で重要) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 心得: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・「速い」は定量的に語る │ │
│ │ ・平均値より分布(パーセンタイル)を見る │ │
│ │ ・飽和点の手前で運用する │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
次のステップ
- パフォーマンスの法則(発展) - リトルの法則、アムダールの法則
- ボトルネックの見つけ方 - どこから調べるか