ひとことで言うと#
本番環境で想定されるトラフィックを人工的に再現してシステムに投入し、レスポンスタイム・スループット・エラー率などを計測して性能のボトルネックや限界値を特定するテスト手法。
押さえておきたい用語#
- RPS(Requests Per Second)
- 1秒あたりのリクエスト数。システムのスループットを測る基本指標。
- パーセンタイル(p50/p95/p99)
- レスポンスタイムの分布を示す指標。p99は全リクエストの99%がこの時間内に完了することを意味する。
- ランプアップ
- 負荷を徐々に増加させること。いきなり最大負荷をかけるのではなく段階的に上げてボトルネックを特定する。
- 変曲点
- 負荷の増加に対してレスポンスタイムが急激に悪化し始めるポイント。システムのキャパシティ限界を示す。
- サチュレーション
- CPU・メモリ・DB接続プールなどのリソースが飽和状態に達すること。変曲点の主因となる。
負荷テスト手法の全体像#
こんな悩みに効く#
- セール時にアクセスが集中してシステムが落ちた経験がある
- 「何人まで同時にアクセスできるか」を聞かれても答えられない
- 本番で初めて発覚する性能問題を事前に防ぎたい
基本の使い方#
何を検証したいかによってテストの種類を選ぶ。
- 負荷テスト(Load Test): 想定ピーク負荷でのレスポンスタイムを確認
- ストレステスト(Stress Test): 限界を超えた負荷での挙動を確認
- 耐久テスト(Endurance Test): 長時間の連続負荷でメモリリーク等を検出
- スパイクテスト(Spike Test): 突発的な負荷急増への耐性を確認
ポイント: 目的なく負荷をかけても意味がない。「何を知りたいか」を明確にする。
実際のユーザー行動を再現するシナリオを作る。
- 本番のアクセスログから行動パターンを分析する
- 主要なユースケース(ログイン→検索→購入 等)をスクリプト化する
- 同時接続数、リクエスト/秒、ランプアップ時間を定義する
ポイント: 単一APIへの連打ではなく、実際のユーザー行動に近いシナリオを作る。
負荷テストツールでシナリオを実行する。
- k6、Gatling、JMeter、Locustなどのツールを活用
- レスポンスタイム(p50/p95/p99)、スループット、エラー率を記録
- サーバー側のCPU、メモリ、DB接続数、キュー長なども同時に記録
ポイント: クライアント側のメトリクスだけでなく、サーバー側のリソース使用率も同時に見る。
ボトルネックを特定し、改善策を立てる。
- レスポンスタイムが悪化し始めるポイント(変曲点)を見つける
- CPU、メモリ、DB、ネットワークのどれが制約になっているか特定する
- 改善後に再テストし、効果を定量的に確認する
ポイント: 負荷テストは1回やって終わりではなく、改善→再テストのサイクルで回す。
具体例#
目的: 年末セールで通常の10倍のアクセスが見込まれる。システムが耐えられるか事前検証。
シナリオ設計: 本番ログから分析。60%が商品閲覧、25%がカート操作、15%が決済。k6でスクリプト化。
テスト結果:
- 通常負荷(500 RPS): p99 150ms、エラー率 0.01% → OK
- 想定ピーク(5,000 RPS): p99 800ms、エラー率 0.5% → 許容範囲ギリギリ
- 限界テスト(8,000 RPS): p99 5秒超、エラー率 15% → DBの接続プールが枯渇
改善: DB接続プール拡大 + 商品一覧のキャッシュ導入 → 再テストで10,000 RPSまで p99 300ms で安定。セール当日のピーク7,000 RPSを問題なくさばけた。
状況: 本番環境で週に1回、APIサーバーが応答しなくなりOOM Killerで強制終了。通常の負荷テストでは再現しない。
耐久テスト実施: 本番同等の負荷(200 RPS)を24時間連続投入。
発見: 8時間経過後からメモリ使用量が線形に増加。12時間後にp99が3秒を超過。原因はHTTPクライアントの接続プールが正しくクローズされておらず、リクエストごとにソケットがリークしていた。
修正: HTTPクライアントのdefer resp.Body.Close()漏れを修正。再テストで24時間後もメモリ使用量が安定(1.2GB→0.4GBで安定)。週次のOOM Killerが完全に解消。
状況: TV CMの放映後にアクセスが瞬間的に20倍になることが予想される。ECSのオートスケーリングが間に合うか検証。
スパイクテスト: 通常負荷(300 RPS)→ 30秒で6,000 RPSに急増 → 5分維持 → 300 RPSに戻す。
結果: スケールアウト開始まで90秒。その間にp99が8秒に悪化し、エラー率12%。CMの視聴者がアクセスする最初の90秒間にユーザーが離脱する問題。
対策: CM放映15分前にPre-warmでタスク数を事前に3倍に増加する運用ルールを策定。再テストでスパイク時もp99 400ms、エラー率0.1%以下を達成。
やりがちな失敗パターン#
- 本番と異なる環境でテストする — ステージング環境のスペックが本番より低いと、結果に意味がない。本番同等の環境でテストするか、差分を考慮して結果を補正すること
- シナリオが非現実的 — 全ユーザーが同じAPIを同時に叩くようなシナリオは、実際の負荷パターンと異なる。本番のアクセスログに基づいたシナリオを作ること
- テスト結果を報告するだけで終わる — 「p99は1秒でした」と報告しても、それが良いのか悪いのか判断基準がない。事前に合格基準を定義し、合否を明確にすること
- 負荷テストを本番リリース直前にしかやらない — 問題が見つかっても修正する時間がない。開発サイクルの早い段階から定期的に実施すること
まとめ#
負荷テストは 「本番で起きる前に問題を見つける」 ための重要なプラクティス。目的を明確にし、現実的なシナリオで実行し、結果から改善につなげるサイクルを回すことが大事。特に大規模イベント前やアーキテクチャ変更時には必ず実施しよう。