Contents
失敗しない負荷試験のやり方:k6でボトルネックを可視化して“落ちる前”に潰す実践ガイド
「リリース後に急に遅くなった」「ピーク時だけ落ちる」「なぜか一部の操作だけタイムアウトする」——性能問題は、機能が正しくても起きます。そして一度炎上すると、原因調査・暫定回避・説明対応に人が吸われ、PM/管理職は意思決定が遅れ、QAは再現条件に悩み、開発は“勘”で修正しがちです。そこで効くのがk6による負荷試験です。負荷をコードで再現できるため、同じ条件で何度でも測れます。この記事では、現場で迷いがちな負荷試験の進め方を、設計→実装→観測→改善→定着まで一気通貫で整理し、ボトルネックを「見える化」して改善に落とす(性能ボトルネックの特定・遅延原因の切り分け)ところまで、実務で回せるレベルに落とし込みます。
この記事で得られること
- 合格/不合格を先に決める負荷試験の設計テンプレ
- k6ロードテスト/k6性能試験で“現実に近い負荷”を作る考え方
- k6結果と監視/ログ/トレースを突き合わせてボトルネックを特定し、改善優先度を決める手順
1. なぜ今「k6で負荷試験」なのか:炎上の芽を“数字”で潰す
性能問題が厄介なのは、ユーザー数やデータ量が増えた瞬間だけ顕在化し、しかも「たまに」「特定条件で」起きることです。機能テストやE2Eが通っていても、同時アクセスや外部依存の遅延が加わると、スレッド/イベントループ、DBコネクション、キュー、ロック、キャッシュが一気に詰まります。結果としてp95/p99が跳ね、タイムアウトが増え、エラー率が上がり、ユーザー体験が崩れます。ここで重要なのは、平均応答時間だけでは“尾の遅さ”が隠れる点です。PMや管理職が見るべきは、p95/p99(遅い人がどれだけいるか)と、エラー率・スループット(処理量)・飽和点(どこで頭打ちになるか)です。
k6の負荷試験は、こうした議論を「感想」から「数値と再現性」に変えます。たとえば「キャンペーンでアクセスが3倍」という曖昧な不安も、k6性能試験で到達レートや同時ユーザーを段階的に上げれば、どの段階でp99が崩れ、エラーが出るかが見えます。さらに、スクリプトが資産になるので、次のリリースでも同じ手順を回し、性能劣化(回帰)を早期に検知できます。
現場でよくある“損”は、性能問題が発生してから「原因はDB?アプリ?インフラ?」の議論を始めてしまうことです。k6で事前に負荷を与え、ボトルネックを可視化しておけば、障害時の初動が変わります。「どの操作が」「どの負荷で」「どの指標が崩れるか」が分かっているため、切り分けが早く、暫定策(レート制限、キャッシュ、機能フラグ、非同期化)も打ちやすい。結果として、PMは説明責任を果たしやすく、管理職は投資判断(スケールか改善か)を根拠付きで出せます。SNSでバズる“落ちた話”に寄せるのではなく、落ちる前に定着させることが、現場の火消し工数を最も減らします。
2. 負荷試験の全体設計:目的→指標→シナリオ→合否基準の順で決める
実務で最初にやるべきは、ツールの選定ではなく「何を証明したいか」の言語化です。負荷試験は目的で設計が変わります。キャパ確認なら「どこまで耐えるか」を知りたいので、段階的に負荷を上げて飽和点を探します。ボトルネック可視化なら「どこが詰まるか」を知りたいので、システムが崩れ始める直前の負荷で一定時間押し続け、観測データを厚く取ります。回帰性能テストなら「前回より遅くなっていないか」を知りたいので、条件を固定し、閾値を機械判定できる形にします。耐久/スパイクなら「時間と変化」を再現し、リークや枯渇、ピーク瞬間の崩壊を見ます。
次に指標です。現場では「平均が○msならOK」という発想になりがちですが、ユーザーの不満は尾で生まれます。したがって合否基準は、p95/p99、エラー率、スループットを中心に置きます。たとえば「主要APIのp95が800ms未満、p99が1500ms未満、HTTP 5xxが0.1%未満、かつ一定RPSを維持できる」といった形です。この合否基準をk6のthresholdに落とし込むと、性能テストの進め方が“毎回同じ”になります。
「どのくらいの負荷をかけるか」は、勘ではなくデータで決めるのが基本です。アクセス解析やログからピーク時間帯のRPS、同時ログイン数、導線の割合(検索:詳細:購入など)を把握し、まず“現実のピーク”を再現します。次に「ピークの1.5倍/2倍」など、事業計画に沿った将来負荷を設定します。もし数字がない場合は、同時ユーザー数 × 1ユーザーの操作頻度で概算し、仮説として置きます。ここで大事なのは、仮説でもよいので“合意された前提”を作ることです。前提が揃っていれば、k6の結果がそのまま意思決定材料になります。
例として、ピーク時の同時ログインが2,000人、平均して「10秒に1回」操作が発生するなら、概算の到達レートは約200RPSです(2,000 ÷ 10)。ここから「重要導線の比率が30%」なら、そのAPIに60RPS相当が集中する前提になります。こうした前提を置いたうえで負荷試験を設計すると、負荷試験の設計が“説明できる”状態になります。PMはこの前提と結果をセットで共有し、QAは同じ前提で再実行し、開発はボトルネック可視化の対象を絞れます。前提が揺れる場合も、スクリプトとメトリクスが残るため、議論が空中戦になりません。
最後にシナリオ(負荷モデル)を決めます。VU(同時ユーザー)で押すクローズドモデルは、ユーザーが待って次の操作をする状況を表現しやすい一方、到達RPSが自然に変動します。到達率で押すオープンモデル(一定RPSで叩く)は、キャパ境界の把握や回帰に強い反面、バックエンドが詰まると待ち行列が発生し、実ユーザー体験とずれる可能性があります。目的に合わせて到達率重視と行動重視を使い分けるのが、失敗しない負荷試験の進め方です。
合否基準(SLO)を先に決めるコツ
「速くなった/遅くなった」を議論すると揉めます。最初に“ユーザー体験として許容できる遅さ”と“許容できないエラー率”を決め、k6のthresholdで自動判定できる形にしておくと、会議は“好み”ではなく“基準未達の原因”に集中します。PM/管理職はSLOを事業KPI(離脱率、購入完了率、問い合わせ件数)と紐づけておくと、改善の優先順位が付けやすくなります。
3. k6導入の最短ルート:再現性のあるシナリオを作るテンプレ
k6の導入は、スクリプトを書く前に「安全に回せる環境」を整えるのが実務の近道です。まず、対象環境(本番・ステージング・専用性能環境)を決め、テスト用のデータ(ユーザー、商品、検索対象、権限)を用意します。外部課金やメール送信など“実害が出る処理”はモック化し、IP制限やWAF、レート制限の扱いも事前合意しておきます。ステージングで負荷がかけられない場合は「性能テスト専用の最小環境」を用意し、データ量だけは本番相当(もしくはスケール比を明示)にするのが現実的です。
k6の起動自体はシンプルで、ローカルでもCIでも回せます。たとえばMacならHomebrewで導入し、Dockerでも動きます。重要なのは「実行方法を標準化」し、誰が回しても同じコマンド・同じ設定になることです。環境変数でベースURLやトークンを差し替えられるようにしておくと、QAでもPMでも扱いやすくなります。
スクリプト設計は「小さく始めて、目的に合わせて増やす」が正攻法です。最初は主要エンドポイントを1〜2本に絞り、チェック(期待値)とthreshold(合否)を入れます。たとえばHTTP 200以外をエラー扱いにし、p95や失敗率で判定します。次に、待ち時間(think time)や分岐を入れて“人の操作”に近づけます。ログインが必要なら、事前にトークンを用意して配る方式(テストユーザーを複数用意してローテーション)にすると、認証のボトルネックを意図せず踏みにくくなります。一方、認証が本当に重要な性能ポイントなら、ログインもシナリオに含めて測ります。ここは目的に合わせて切り替えます。
また、テストデータの偏りは結果を歪めます。検索キーワードが1種類だけだとキャッシュが効きすぎますし、逆に毎回ユニークなデータだとキャッシュが効かなすぎる。実ユーザーの分布(人気商品、人気検索語)を参考に、固定とランダムを混ぜるのがコツです。負荷試験は「再現性」と「現実性」のバランスが重要で、回帰用途は再現性優先、ボトルネック可視化用途は現実性も取りに行く、と使い分けると運用が楽になります。
// k6 性能試験のthreshold例(イメージ)
export const options = {
thresholds: {
http_req_failed: ['rate<0.001'], // 失敗率0.1%未満
http_req_duration: ['p(95)<800', 'p(99)<1500'] // p95/p99の目標
}
};
4. ボトルネック可視化のやり方:k6結果×監視データで“原因”まで落とす
負荷試験の結果は、単体で眺めても「遅い/速い」しか分かりません。実務で価値が出るのは、k6のp95/p99・エラー率・スループットの変化を、同じ時刻の監視データと重ねることです。遅延が跳ねたタイミングに合わせて、アプリのログ(遅いリクエスト、例外、タイムアウト)、DBメトリクス(コネクション、ロック待ち、スロークエリ)、インフラ(CPU、メモリ、IO、ネットワーク)、外部APIの待ち時間がどう動いたかを確認します。これが遅延原因の可視化であり、性能ボトルネック特定の最短ルートです。
現場でおすすめの手順はシンプルです。まずStep1として、ロードテストの結果から「崩れ始めた指標」を1つ決めます(例:p99が急上昇、またはhttp_req_failedが増加)。次にStep2で、同時刻の監視ダッシュボードを開き、CPU/メモリ/IO/コネクション/外部依存をざっと俯瞰して“怪しい箇所”を絞ります。最後にStep3で、ログやトレースから具体の根拠(遅いSQL、特定エンドポイント、外部APIの遅延、ロック待ち)を取ります。ここまで行けば、ボトルネックが「なんとなく」ではなく「修正できる単位」に落ちます。
読み解きのコツは「現象→候補→確証」の順です。たとえば、p99だけが跳ね、エラー率は低い場合、キューイングやロック競合、GC、外部依存の遅延など“たまに長く待つ”要因が疑われます。一方、スループットが頭打ちでエラーが増えるなら、コネクション枯渇、スレッド不足、CPU飽和、レート制限など“飽和”が濃厚です。ここでありがちな誤解は「CPUが高い=CPUが原因」と短絡することです。DBロック待ちでアプリがスレッドを掴み続け、結果としてCPUが高く見える、という逆転も起こります。だからこそボトルネック可視化は、単一指標ではなく、複数の観測点を時刻で揃える必要があります。
よくある性能ボトルネックのパターンも、負荷試験では見え方が変わります。たとえば「DBコネクション枯渇」は、スループットが頭打ちになり、p95/p99がなだらかに悪化した後にエラー率が増えます。「ロック競合」は、平均はそこそこでもp99だけが極端に伸び、遅いSQLや特定更新系APIに偏ります。「外部API待ち」は、外部依存の待ち時間と同期してp95/p99が跳ね、リトライが入ると急に増幅します。こうした特徴を押さえておくと、切り分けが早まり、次の一手が即決できます。改善の一例として、接続プール上限の調整、インデックス追加、キュー化、タイムアウト短縮+サーキットブレーカ導入などを選択肢として整理しておくと、PM/管理職の判断も速くなります。
“観測”が薄いと負荷試験が無意味になる
負荷試験を回す前に、最低限「リクエストIDのログ」「遅いSQLやエンドポイントの可視化」「DB/アプリの主要メトリクス」を揃えてください。可能なら分散トレーシングを入れ、1リクエストがアプリ→DB→外部APIのどこで時間を使っているかを追えるようにすると、遅延原因の可視化精度が一気に上がります。計測がないと、性能改善が“当てずっぽう修正”に戻ってしまいます。
5. 実戦で使える負荷試験シナリオ:スパイク・耐久・回帰を分けて回す
現場で役に立つのは、1回きりの大規模テストより「用途別の小さな型」を複数持つことです。まず回帰性能テストは、毎回の改修で性能が落ちていないことを守るためのテストです。ここでは条件を固定し、k6性能試験のthresholdで合否を自動判定できるようにします。対象は“売上や業務に直結する導線”に絞り、5〜10分で回る軽量版を用意すると、CI/CDにも載せやすくなります。ポイントは、同じデータ、同じ負荷、同じ時間帯で回し、比較がぶれないようにすることです。
次にスパイクテストは、キャンペーンや告知直後の急増を想定し、短時間で負荷が跳ねる形を作ります。急上昇で一時的にキューが溜まり、回復に時間がかかるなら、スケールやキャッシュ、リトライ戦略に課題がある可能性が高いです。ここでの落とし穴は、キャッシュが温まっていない状態(コールドスタート)と温まった状態(ウォームアップ)で結果が大きく変わることです。手順として、ウォームアップ→本番負荷の二段階にすると、現場に近い数字が出ます。
耐久テストは、時間が経って初めて表に出る問題(メモリリーク、コネクションのじわじわ枯渇、ログ肥大、ディスクIO悪化)を捕まえるのに向きます。夜間バッチと日中トラフィックが重なる現場なら、一定負荷を維持しつつ、周期的に重い処理を挟む負荷試験が有効です。最後にキャパ確認は、段階的に負荷を上げて飽和点を見つけ、どこまでスケールさせればよいかの投資判断に直結します。PM/管理職にとっては「目標RPSを達成するために、どのボトルネックを潰す必要があり、どの改善が最短か」を説明できる材料になります。
6. 改善と運用定着:測る→直す→守る(CI/CDと体制)
負荷試験は“測るだけ”では終わりません。重要なのは、結果をもとに改善を優先順位付けし、再発しない仕組みに落とすことです。優先順位は、影響範囲(主要導線か)、頻度(常時かピーク時だけか)、回避可能性(暫定策があるか)、修正コスト(短期で効くか)で決めると合理的です。短期で効く改善は、DBインデックスやクエリ改善、N+1の解消、キャッシュ導入、接続プール設定、タイムアウト/リトライ設計の見直しなどが代表例です。中長期では、非同期化、分割、スケール戦略、アーキテクチャの見直しが効きます。どの施策も、再計測して改善が確認できて初めて“完了”になります。
定着の要は、二層の自動化です。ひとつは軽量の回帰(短時間・重要導線のみ)をCIに組み込み、性能劣化をPR単位で止めること。もうひとつは、夜間や週次で重い負荷試験を回し、耐久やスパイクを含む“現実の怖さ”を継続的に再現することです。加えて、チームのDefinition of Doneに「主要導線の性能試験が合格している」を含めると、性能が後回しになりにくくなります。ガバナンスとしては、Performance Budgetを置き、p95/p99やエラー率の上限を明示すると、仕様変更や追加機能の議論が建設的になります。
最後に、社内に根付かせるなら「誰が見ても同じダッシュボード」と「同じ実行手順」をセットで作るのが最短です。結果(p95/p99、失敗率、スループット)と、原因特定に必要な監視(DB/アプリ/外部依存)を一枚の画面にまとめ、結果レビューの観点を固定します。これだけで属人化しにくくなり、回帰の取りこぼしも減ります。
運用体制としては、PMがSLOと合否基準を管理し、QAが再現条件と品質ゲートを整え、開発/インフラがボトルネック可視化と改善を担当します。レポートは「結論(合否)」「崩れたポイント」「根拠(メトリクス/ログ/トレース)」「次の一手(短期/中期)」の4点に絞ると、共有が早いです。さらに、内部ナレッジとして「監視設計の基本(仮)」「性能改善の進め方(仮)」「CI/CDに組み込むテスト自動化(仮)」のような関連記事へリンクすると、学習と運用の両方が加速します。
相談が増えるポイント:k6だけでは解けない“設計の歪み”
負荷試験の結果、単純なチューニングでは改善しないケースもあります。その場合は、監視設計(メトリクス/ログ/トレース)を見直し、システムの責務分割や非同期化など“設計”から手当てすると改善が早いことが多いです。株式会社ソフィエイトでは、負荷試験の整備から、ボトルネック可視化、改善の伴走まで支援可能です。まずは現状の負荷試験の設計・観測・基準づくりからご相談ください。
まとめ:k6負荷試験を“イベント”ではなく“仕組み”にする
負荷試験で最も大切なのは、ツール操作ではなく「目的→指標→合否→シナリオ→観測→改善」の順で、誰でも再現できる型を作ることです。k6は同じ条件で何度でも測れるため、性能品質を“守れる形”にできます。さらに、結果を監視データと突き合わせれば、ボトルネック可視化(遅延原因の可視化)から性能ボトルネック特定まで進められます。最初は小さく、重要導線の回帰から始め、スパイク・耐久・キャパ確認へ広げると、性能テストが現場に定着します。この型を“いつもの工程”にすることが、最短の安定化です。
文字数:7861字(本文テキスト、タグ除く・概算)
株式会社ソフィエイトのサービス内容
- システム開発(System Development):スマートフォンアプリ・Webシステム・AIソリューションの受託開発と運用対応
- コンサルティング(Consulting):業務・ITコンサルからプロンプト設計、導入フロー構築を伴走支援
- UI/UX・デザイン:アプリ・Webのユーザー体験設計、UI改善により操作性・業務効率を向上
- 大学発ベンチャーの強み:筑波大学との共同研究実績やAI活用による業務改善プロジェクトに強い
コメント