性能テスト・負荷テスト
性能テストを「速い/遅い」を測る作業ではなく、SLO達成とボトルネック特定のための実験として設計する。普遍的な考え方と、現代ツールのざっくり比較表をまとめます。
性能テストと負荷テスト(Load)の関係
仮説を置いて、再現可能な条件で、システムの限界と弱点を見つける実験です。
ここでの位置づけは次の通りです。
- 性能テスト(Performance Testing): 上位概念(性能を様々な条件で検証する)
- 負荷テスト(Load Testing): 性能テストの一種(想定〜ピーク負荷での挙動を検証する)
用語整理(このドキュメントの呼び方)
結論から言うと、標準的な定義では 「性能テスト(Performance Testing)」が上位概念で、その一種が「負荷テスト(Load Testing)」 です。 一方で日本語の現場では「負荷テスト」という言葉が 性能テスト全般(ロード/ストレス/スパイク/ソーク等)をまとめて指すこともあり、会話だけだとズレやすいです。
このドキュメントでは混乱を避けるため、以下のルールで呼び分けます。
- 「性能テスト」: 上位概念としての話(目的、指標、進め方など“全般”)
- 「負荷テスト」: Load Testing を指す(想定〜ピーク負荷)
- Load以外は「ストレステスト」「スパイクテスト」「ソーク(耐久)テスト」「キャパシティテスト」と書く
| 呼び方 | 位置づけ | ざっくり何をする? | 何が分かる? |
|---|---|---|---|
| 性能テスト(Performance Testing) | 上位概念 | 性能(応答/スループット/安定性/資源効率/スケール)を様々な条件で測る | SLO達成可否、劣化傾向、改善余地 |
| 負荷テスト(Load Testing) | 性能テストの一種 | 想定〜ピークの負荷(同時ユーザー/RPS等)で振る舞いを見る | 想定負荷で壊れないか、どの辺から苦しくなるか |
| ストレステスト(Stress Testing) | 性能テストの一種 | 想定を超えて負荷を上げ、限界点と壊れ方を見る | 限界点、フェイルの仕方、回復性 |
| ソーク/耐久テスト(Soak/Endurance) | 性能テストの一種 | 中〜高負荷を長時間かけ続ける | メモリリーク、枯渇、劣化の蓄積 |
| スパイクテスト(Spike) | 性能テストの一種 | 短時間で急増/急減させる | バースト耐性、回復の速さ |
※ 定義は団体/ベンダーで表現が少し違いますが、「性能テストが上で、負荷テストはその一部」という関係は概ね共通です。 参考:
- ISTQB glossary: Performance testing
- ISTQB glossary: Load testing
- Microsoft: Performance test / load test
- AWS Well-Architected: performance testing
性能テストはなぜ行うのか(そもそもの目的)
結論として、性能テストの目的は 「想定される(または最悪の)負荷条件で、サービスが約束(SLO/UX/安全性)を守れるかを、再現可能に検証して“失敗の仕方”まで把握すること」 です。
さらに一段抽象化すると、負荷というストレスをかけたときに、システムがどう振る舞うかを実験で理解し、予測可能にすることです。 そして、それをする理由は結局 本番で起きる高コストな失敗(障害・炎上・機会損失)を、事前に安く・安全に・再現可能に潰すためです。
- ユーザー体験の保証: 想定トラフィックで p95/p99 が許容範囲か、タイムアウト/エラーが増えないか
- 限界点とボトルネック特定: どこ(DB/外部API/キュー/コネクション/CPU/IO)が先に詰まるか
- キャパシティ計画: 「今の構成で何RPS(Requests Per Second)まで」「何を増やすと伸びるか」を数字で持つ
- スケール/保護機構の検証: オートスケール、レート制限、リトライ等が期待通り動くか
- 回帰検知: リリースや設定変更で性能(特にテイル)が悪化していないか
それぞれはどの“種類”のテストに関係する?
上の箇条書きは「目的/観点」で、そこから「どの種類の性能テストをやるか」を選びます(1対1ではなく、複数が当てはまることがあります)。
| 目的/観点 | 関連するテスト種別(例) |
|---|---|
| ユーザー体験の保証 | 負荷テスト(Load)、ソーク(耐久) |
| 限界点とボトルネック特定 | ストレステスト(Stress) |
| キャパシティ計画 | キャパシティテスト(Capacity)(実施形態として負荷/ストレスを使うことも多い) |
| スケール/保護機構の検証 | 負荷テスト(Load)、スパイクテスト(Spike)、(場合により)ストレステスト |
| 回帰検知 | 既定シナリオの性能テストをベンチマーク化して継続実行(多くは負荷テストで実施) |
性能テストで得られるメリット / デメリット(負荷テストを含む)
メリット
- 本番前に弱点が見える: 限界点・詰まり(サチュレーション)・依存先の律速を早めに発見できる
- 数字で意思決定できる: 「どこまで出せるか」「何を変えるとどれだけ効くか」を比較できる(勘や体感に頼らない)
- 回帰を早期に検知できる: リリースや設定変更で p95/p99 やエラー率が悪化していないかを継続的にチェックできる
- 運用の不安が減る: アラート設計、オートスケール、レート制限などの運用機構も含めて検証できる
デメリット(コスト・注意点)
- 時間とコストがかかる: シナリオ作成、テスト環境整備、データ準備、観測、解析に工数が必要
- 現実を完全には再現できない: キャッシュ、データ分布、ユーザー行動、外部要因(ネットワーク/依存先)で結果がズレる
- 観測が弱いと「分かった気」になる: 原因が特定できないまま終わりやすい(メトリクス/トレース/ログが必須)
- 環境に影響を与える: テスト環境でもDBを痛めたり、依存先に迷惑をかける可能性がある(制限や隔離が必要)
まず決めるべきこと(試験の目的)
- SLOを満たせるか確認したい 例: 「p95 300ms以下」「エラー率 0.1%以下」「月間可用性 99.9%」など
- ボトルネックを特定したい 例: DB、外部API、キャッシュ、コネクションプール、ロック、CPU、I/O
- スケール戦略を検証したい 例: オートスケールが効くか、キューで吸収できるか、上限はどこか
- リリース前の回帰検知をしたい 例: 以前よりp99が悪化していないか、リソース効率が落ちていないか
目的が曖昧だと、結果が「なんとなく速い/遅い」で終わりがちです。
目的によって試験の進め方は変わる?
変わります。目的ごとに「負荷の作り方」「観測すべき指標」「合否判定(または成果物)」が変わります。
| 目的 | 進め方(負荷のかけ方) | 何を見る(合否/成果) |
|---|---|---|
| SLOを満たせるか確認 | 想定トラフィックで定常状態を一定時間維持(Load/Soak寄り) | p95/p99、エラー率、タイムアウト率がSLO内か |
| ボトルネック特定 | 低負荷→段階的に上げる Ramp/Stress で崩れ方を見る | 律速箇所(DB/依存先/コネクション等)と次の打ち手の仮説 |
| スケール戦略検証 | スケールアウトが発火するよう負荷をかけ、スケールに要する時間も測る(Spikeも有効) | スケール中のSLO逸脱、回復可否、保護機構(レート制限等)の動作 |
| 回帰検知 | 条件固定で毎回同じシナリオを再現し、前回/基準と比較 | p95/p99、エラー率、リソース効率の悪化が許容範囲内か |
見るべき指標(性能テスト全般で共通)
レイテンシ(特にテイル)
- p50 / p95 / p99: 平均より「遅い人」を見る(ユーザー体感はテイルが支配しやすい)
- 分解: DNS/接続/待ち/処理/DB/外部API など、どこに時間があるか
スループット
- RPS/TPS: どれだけ処理できたか(ただし、速い=良いではなく「SLOを満たしながら」が条件)
エラー
- HTTP 5xx/4xx、タイムアウト、リトライ回数 タイムアウト増は「遅い」ではなく「壊れ始めている」兆候です。
サチュレーション(詰まり)
- CPU/メモリだけでなく、DB接続枯渇、スレッド枯渇、キュー滞留、I/O待ち、外部APIのレート制限など
観測はよく「RED(Rate/Errors/Duration)」や「Golden Signals(Latency/Traffic/Errors/Saturation)」で整理できます。
性能テストの種類(使い分け)
| 種類 | 目的 | 代表的なやり方 |
|---|---|---|
| Load | 想定負荷でSLO達成 | 想定トラフィックで定常状態を維持 |
| Stress | 限界点・崩れ方の把握 | 徐々に上げてどこで壊れるかを見る |
| Spike | 急増への耐性 | 瞬間的に跳ね上げる(SNS拡散など) |
| Soak | 長時間の劣化検出 | メモリリーク、枯渇、GC悪化を炙る |
| Capacity | 受け入れ上限の見積り | 「いまの構成で何まで」→増設計画へ |
シナリオ設計(現実に寄せる)
ユーザー行動にする(単一APIだけにしない)
例:
- ログイン → 一覧 → 詳細 → 更新
- 検索 → 絞り込み → 購入 → 決済(外部連携)
データを現実に寄せる
データが少ないとインデックスやキャッシュが効きすぎて、本番より良い結果になります。 逆に、毎回同じIDを叩くとキャッシュが効きすぎます(ホットキー問題も起きます)。
ワークロードモデル(ここが精度を左右)
負荷の作り方は大きく2系統です。
-
Open model(到着率): 例「毎秒200リクエスト来る」 インターネットの流入に近い。飽和すると待ち行列が伸び、レイテンシが崩れるのが見えやすい。
-
Closed model(同時ユーザー): 例「同時200ユーザー」 レイテンシが伸びると、その分リクエスト発行が遅くなり到着率が落ちる(現実とズレることがある)。
どちらでも良いのではなく、目的に合うモデルを選ぶのが重要です。 (例: “SNS流入の急増”を見たいなら到着率モデルが合いやすい)
試験の進め方(テンプレ)
- 前提: 環境・構成・データ量・キャッシュ状態を固定(差分が結果を歪める)
- Warm-up: JIT/キャッシュ/コネクション確立のための準備運転
- Ramp: 徐々に上げる(いきなり最大にしない)
- Steady: 定常を維持して観測(ここが本番)
- Cool-down: 終了後の回復具合も見る(スレッド/コネクションが戻るか)
- 再現性: 同条件で複数回(「たまたま速い/遅い」を排除)
よくある落とし穴(時代が変わっても同じ)
- キャッシュで“良く見える”(本番の分布と違う)
- 外部APIが律速(レート制限・遅延・障害注入)
- メトリクスが足りず原因不明(観測不足が最大の敵)
- 負荷装置が先に限界(クライアントCPU/ネットワーク/コネクション数)
- オートスケールの遅さ(スケールアウトの時間=実害)
- コネクションプール枯渇(DB/HTTPクライアント/スレッド)
- “平均”だけ見て安心する(p99が地獄、が典型)
結果のまとめ方(読む人に優しい)
最低限これだけあると意思決定に使えます。
- 条件: 構成、バージョン、データ量、キャッシュ状態、実行時間、負荷モデル
- 結果: p50/p95/p99、RPS、エラー率、サチュレーションのピーク
- 結論: SLOを満たした/満たさない、限界点、次の打ち手
- 打ち手: 何を変えるとどれだけ改善する見込みか(仮説→再試験)
現代のツール(ちらっと比較表)
「何を測るか(HTTP/API/ブラウザ/キュー)」で選ぶのが基本です。
| 目的 | ツール例 | 特徴 |
|---|---|---|
| HTTP/API の負荷生成 | k6 / Locust / JMeter / Gatling / Artillery | シナリオ駆動。到着率/同時数などモデル選択がしやすい |
| 高速・単機能ベンチ | wrk / wrk2 / vegeta | 単純なHTTPを高RPSで叩く(再現性は高いがシナリオは弱め) |
| ブラウザE2E負荷(UI体感) | Playwright / Puppeteer | フロント描画やJS実行を含む(重いので台数が必要) |
| 観測(メトリクス/トレース/ログ) | Prometheus+Grafana / OpenTelemetry / Datadog / New Relic | 性能テストは「観測できるか」が勝敗を分ける |
| 障害注入(レジリエンス) | AWS FIS など | 遅延/停止/ネットワーク断で「壊れ方」を検証 |
すぐ使えるチェックリスト
- 目的: SLO検証?ボトルネック探索?回帰?
- モデル: 到着率(open) or 同時ユーザー(closed)
- 観測: p95/p99、エラー率、サチュレーション、依存先のメトリクス
- 再現性: 条件固定、複数回、差分があれば理由を記録
- 安全: 本番実施はレート制限・影響範囲・ロールバック計画を用意