はじめに
どうしたら性能テストにおいて本番同等の状況を再現できるだろうか?
性能テストって果てしなくやれちゃう気がするけどどこまでやったらよいの?
本概論では確立されたプロセス・プラクティスに基づいて性能目標設定と計画立案、負荷ツールの選定、テストシナリオ作成・環境構築・データ準備などの準備、性能テストの実施と結果の分析、ボトルネック分析およびチューニング・再テストに至るまで「性能テストをきちんとやる」ための標準的なプロセスを紹介します。
- 性能テストの勘所
- 目的と性能目標
- テスト計画
- 負荷ツール選定
- テストシナリオ作成
- 環境構築
- データ準備
- 性能テスト実施
- 評価・改善
- 結果まとめ
本概論は、Webシステムのオンライン同期処理(クライアントがサーバの処理を呼び出し、処理の完了を待って応答を受け取る処理)のうちAPIを主な対象として想定しています(🔍A)。
みなさまのシステムやプロジェクトがおかれた状況にとって最適な性能テストを行うための一助となれば幸いです。
1.性能テストの勘所
性能テストにはさまざまな種類があり、目的に応じて選んで実施します。本章ではまず性能テストの種類を紹介し、続いてどの種類の性能テストにも共通するベストプラクティスを紹介します。
1-1.性能テストの種類
性能テストは下記に示すようにさまざまな種類があります。どの種類を実施するかは、目的・ゴール(2-1)に応じてテスト計画で選定します(3-1)。実施の目安は一覧の後の表のとおりです。
- ロードテスト(Load testing)
- いわゆる負荷試験。負荷を目標の負荷(ユーザ数やスループット)まで徐々に増加させたとき、応答目標を満たしていること、リソース消費やボトルネック有無を検証する。想定ピーク時の負荷を目標とするものをピークロードテストと呼ぶ。
- スパイクテスト(Spike testing)
- 短時間に負荷を急増させたときの挙動を検証する。始業時の一斉ログインやセール開始直後のように、瞬間的なアクセス集中が想定される場合に実施する。急増が収まった後に元の性能へ戻るかも確認する。オートスケールを使う環境では、台数の増加が負荷の急増に追従できるかも確認する。
- スケーラビリティテスト(Scalability testing)
- 業務量の増加に対し、スケールアップ(サーバのスペックを上げる)やスケールアウト(サーバの台数を増やす)によって、性能目標を満たしたままスループットを増やせることを検証する。リソースを増やしてもスループットが伸びない場合は、律速している部分(データベースなど、台数を増やせない部分)を突き止める。オートスケールを使う環境では、需要の増加に応じて自動で拡張し、需要が減れば縮小できることもあわせて確認する(急な負荷増に追従できるかはスパイクテストで扱う)。将来の業務量の大幅な増加が想定される場合などに実施する。
- 耐久テスト(Soak or endurance testing)
- いわゆる長期稼働試験(ロングランテスト)。長期に渡ってワークロードを掛け続けシステムリソースや挙動に異常が発生しないことを確認する。メモリリーク、DB接続やファイルハンドルの解放漏れ、ログや一時ファイルの蓄積によるディスク容量の不足、更新・削除の繰り返しによるデータベースの肥大化(PostgreSQL で不要になった行が溜まり、自動バキュームが追いつかないなど)のように、短時間では表出しない性能劣化を確認するために実施する。
- ボリュームテスト(Volume testing)
- データ量を増やしたときの性能劣化を検証する。将来想定されるデータ蓄積量を投入した状態で計測し、想定データ量で性能目標を満たすか、件数の増加に伴って極端に遅くなる処理(全件走査など)がないかを確認する。
- キャパシティテスト(Capacity testing)
- 性能目標を満たしたまま、何人・何件まで処理できるか(上限の値)を求める。ロードテストが目標の負荷で目標を満たすかを確かめるのに対し、負荷を段階的に増やして目標を満たせる上限を決定する。後述のストレステストは限界を超えたときの振る舞い・本テストは限界の手前を見る点で関心が異なる。現在の構成で収容できるユーザ数や、増強が必要になる時期を判断する材料として実施する。不特定多数の個人が利用するWebサービスでは、サーバ1台あたりの処理能力を測り、必要な台数を見積もる材料にする。
- ストレステスト(Stress testing)
- 想定を超えた高い負荷をかけた場合や、使えるリソースが減った場合(一部のサーバが停止して残りのサーバで負荷を受け持つ、バーストクレジットの消尽や他の処理との競合で処理能力が落ちるなど)の性能劣化や挙動を検証する。どこまで耐えられ、限界を超えたときにどう振る舞うか(応答が遅くなる、流量制御で拒否する、停止するなど)を把握し、負荷が収まった後に元の性能へ戻れるかを確認する。限界での挙動や安定性を把握したい場合に実施する。
- 並行実行テスト(Concurrency testing)
- 同じデータや資源に対する操作が同時に起きたときに、ロック待ち・デッドロック・更新の競合による失敗が起きないかを検証する。オンラインショッピングで、同じ商品の在庫を多数の購入者が同時に引き当てる場面などが典型である。組み合わせは無数にあるため、多くの利用者が同じものを更新する箇所、ロックを広く・長く取る処理、業務で実際に重なる操作に絞って実施する。ロードテスト中に見つかった排他競合エラーの原因切り分けとして実施することも多い。
実施の目安は次のとおりです。必須・推奨はすべてのシステムで実施し、それ以外はシステムの特徴に応じて追加します。
| 区分 | 実施するテスト |
|---|---|
| 必須 | ロードテスト、ボリュームテスト(※) |
| 推奨 | + 耐久テスト |
| 負荷の増減に処理能力の拡縮で対応するシステム | + スケーラビリティテスト |
| 不特定多数の個人が利用するシステム | + キャパシティテスト、スケーラビリティテスト |
| 瞬間的なアクセス集中が想定されるシステム | + スパイクテスト |
| 社会的に重要なシステム | + ストレステスト |
| 必要に応じて選択的に(区分を問わず) | 並行実行テスト(同じデータを多数の利用者が更新する箇所があるとき) |
※データの蓄積が少ない、または蓄積したデータを検索・集計する処理がないなど、データ件数の増加が処理時間に影響しないことが明らかな場合は省略できます。将来想定されるデータ量を投入したうえでロードテストを実施すれば、ボリュームテストを兼ねられます。
| 📌 テストの種類の呼び方 |
|---|
| テストの種類の呼び方は、組織やプロジェクトによって異なります(「性能テスト」「負荷テスト」などの呼び方が、上記のどれを指すかは一定しません)。テスト計画では、実施する各テストの目的と負荷条件をあわせて定義しておきましょう。 |
1-2.ベストプラクティス
性能テストの種類を問わず、下記はベストプラクティスです。これらが疎かになると、せっかく計測した結果の信頼性が揺らいでしまいます。
(1) 目的とゴールを設定する
性能テストで何を明らかにしたいのか、どうなったら完了なのかを最初に決めます。目的・ゴールが曖昧なままでは、どこまでやれば終わりなのかが決まらず、際限がなくなってしまいます。
🔍詳しくは 2-1.目的とゴールを参照
(2) 本番相当のワークロードを再現する
ワークロード(実業務でサーバに課される負荷の構成)は、出来るだけ本番と同様にします。同一画面・同一パラメータで負荷を掛け続けると、DBキャッシュ等の効果で見かけ上良い数値が出てしまいます。複数画面の組み合わせや各機能の利用割合、画面操作間の待機時間なども再現しましょう。
計測開始直後は負荷が目標に達しておらず、キャッシュも温まっていないため、実際より悪い数値が出ます。終了間際も同様です。ランプアップ・計測区間・ランプダウンを設定し、集計は計測区間を対象に実施しましょう。
🔍詳しくは 3-1.テストシナリオの決定、5.テストシナリオ作成、9-1.計測結果の集計を参照
(3) 本番相当の環境を用意する
サーバのスペックや台数、スケール設定、データ量を本番と揃え、負荷テスト以外のアクセスが発生しない「無風状態」にしたうえで計測を実施します。とくにデータ量は処理時間に影響を及ぼすことが多く、本番より少ないと実際より良い数値が出てしまいます。揃えられない場合は、本番との差異を明らかにしておきましょう。
🔍詳しくは 3-2.体制・スケジュール・環境、6.環境構築、7.データ準備を参照
(4) 合格基準を設定する
性能要求を踏まえて合格基準を仮設定します。実際に計測してみて「非同期処理のレスポンスタイムが未設定だった」と気づくこともあります。この場合は結果に合わせて基準を歪める(単にレスポンスタイムを延ばす)のでなく、性能要求を踏まえて改めて合格基準全体を見直し・合意したうえで、各処理パターンの合格基準へ展開し、再判定します。
🔍詳しくは 2-4.合格基準を参照
2.目的と性能目標
性能テストの目的・ゴールを明確化し、性能要求をもとに性能目標および合格基準を定義します。目的・ゴールは特に重要です。性能テストの目的・ゴールが明確になっていないと、「性能に少しでも関連があるあらゆること」を明らかにしようと際限がなくなってしまう可能性があります。開発資源や時間は有限です。システムが達成すべきビジネス目標や、開発フェーズの位置づけを踏まえ、適切な目的・ゴールを決めましょう。このとき参考となるのは「開発計画」「非機能要件定義」などです。
性能要求・性能目標・合格基準は、次のように段階的に具体化していきます。
| 段階 | 説明 | 例 |
|---|---|---|
| 性能要求 | システムが満たすべき性能を業務の観点で表したもの。非機能要件として定義されます | 通常時:日中、打刻や勤怠の参照が滞りなく行えること(利用者は同時に300人程度) ピーク時:始業時に全社員(3,000人)が15分以内に打刻を終えられること |
| 性能目標 | 性能要求を、テストで検証できる値に置き換えたもの | 通常時:ログイン中ユーザ 300人、スループット 5TPS以上(※1)、レスポンスタイム 2秒以内 ピーク時:ログイン中ユーザ 3,000人、打刻処理のスループット 12TPS以上(※2)、打刻のレスポンスタイム 2秒以内 |
| 合格基準 | 計測値が性能目標を満たしたと判定する条件 | 通常時:打刻・勤怠参照の95%tileが2秒以内 ピーク時:打刻処理の90%tileが2秒以内 エラー率0.5%未満(通常時・ピーク時とも) |
※1 利用者1人あたり1分に1回程度要求を送る(応答1秒+操作の合間59秒)と想定し、300人 ÷ 60秒 = 5TPS とします(🔍F)。
※2 15分間に均等に打刻されるとすれば 3,000件 ÷ 900秒 ≒ 3.3TPS ですが、実際の打刻は始業直前に集中します。ここでは15分間のうち始業直前の5分間に全体の8割(2,400件)が集中すると想定し、2,400件 ÷ 300秒 = 8TPS とします。さらに秒単位の偏りを見込んで1.5倍の12TPSを目標としています。このように、性能要求の期間内で業務量がどう偏るかを想定し、その論拠とあわせて目標値を設定しましょう。
2-1.目的とゴール
| 検討項目 | 説明 |
|---|---|
| 目的 | システムの性能テストで明らかにしたいことを業務目線で定義します。 (例)全社員からのアクセス集中に耐えられることを検証する。アクセスが集中する早朝出社時の打刻が滞りなく行えること。 |
| ゴール | 性能テストを完了と判断する状態を定義します。 単に性能目標がクリアできれば良いのか、限界性能などのシステム性能特性を把握したいのか方針を明確にします。 (例1) 1. 性能目標が達成できること。 (例2) 1. 性能目標が達成できること。 2. 性能目標を超えた過負荷時におけるスループット・レスポンスタイムの性能特性を確認する。 |
ゴールを計測値でどう判定するかは、2-4.合格基準で定めます。
2-2.性能要求の整理
性能目標は、非機能要件として整理された性能要求をもとに設定します。性能要求の整理には、IPAの「非機能要求グレード」などを参考にするとよいでしょう。
業務量は時間帯や時期によって変動することが多くあります。性能要求を整理する際は、通常時の業務量と、業務量が最も多くなるピーク時の業務量を明らかにします。ピーク時については、いつ(時間帯、5・10日、月末月初、年末年始、決算期、不定期のセールなど)、どの業務が、通常時の何倍程度の業務量になるのかを明らかにしましょう。将来の業務量の増加が見込まれる場合は、その増加率もあわせて明らかにします。
業務量は、利用者数の上限を規定しやすいシステムであればログイン中のユーザ数(例:通常時80人、ピーク時600人)で、不特定多数の個人が利用するシステムであれば単位時間あたりの処理件数で表すと、性能目標やテストシナリオにつなげやすくなります(🔍F)。
以降の性能目標・合格基準は、通常時とピーク時のそれぞれについて設定します。
2-3.性能目標の設定
2-2で整理した性能要求をもとに性能目標を設定します。全機能(API)ごとに目標値を定めることは現実的ではないため、機能を処理パターン(詳細表示、検索・一覧、登録・更新、ダウンロードなど)に分け、処理パターンごとに目標値を定めます。業務固有の事情がある機能(業務上とくに速さが求められる、処理が重いなど)は別の処理パターンとして分け、各機能(API)がいずれかの処理パターンに当てはまるようにします。
性能要求として画面単位のレスポンス目標(ユーザの体感レスポンス)が与えられている場合は、画面を構成する処理(API)ごとの目標へ展開します。SPA(Single Page Application)のように1画面の表示で複数のAPIを呼び出す構成では、負荷ツールが計測するのはAPIごとのレスポンスタイムです。画面の体感レスポンスは、APIを順番に呼ぶ場合はそれらの合計、並行して呼ぶ場合は最も遅いものに、ブラウザの描画時間を加えたものになります。個々のAPIが目標を満たしていても画面全体では目標を超えることがあるため、体感レスポンスを踏まえ、代表的な画面について処理パターンごとの目標の目安を決めましょう。
(例)画面の体感レスポンス3秒以内、描画0.5秒、順番に呼ぶAPIが2本の場合、各APIは1.2秒以内((3秒 − 0.5秒) ÷ 2 ≒ 1.25秒)
処理パターンごとの目標は、単純な処理と複雑な処理で分けて設定しましょう。
🔍レスポンスタイムの目安については D.レスポンスタイムの目安を参照
通常時とピーク時のそれぞれについて、下記の項目を定義します。
- クライアント数(ユーザ数)
- スループット目標(サーバ側からみた単位時間あたりの処理件数)
- レスポンス目標(ユーザ側からみた応答時間)
a) クライアント数(ユーザ数)
通常時・ピーク時それぞれの想定ユーザ数を定義します。システムの特性を踏まえ、非アクティブユーザが多い場合はアクティブユーザの割合、ユーザ数の急増が想定される場合はユーザ数増大率を明らかにしたうえで、システムの実態を反映したユーザ数を明らかにします。
b) スループット目標
スループット(Throughput)とは単位時間あたりに処理を完了した件数であり、TPS(Transactions per second:1秒あたりの処理件数)であらわします。1TPSは1秒あたり1件の要求を処理し終えることをあらわします。スループット上限は、H/Wスペック、OSやミドルウェアの性能限界、アプリケーションのボトルネック等によって決まります。
c) レスポンス目標
レスポンスタイムは、クライアントが要求を送り始めてから、サーバの応答をすべて受け取り終えるまでの時間です。性能テストでは、どこからどこまでを測った時間なのかによって、レスポンスタイムとは別にネットワークレイテンシ・サーバ処理時間・TTFBを区別して扱います。
1要求の流れを図示します。
| 用語 | 区間 | 説明 |
|---|---|---|
| ネットワークレイテンシ | ① → ② | 要求がネットワークを通ってサーバに届くまでの遅延(片道)。往復の遅延は RTT(Round Trip Time)と呼ぶ。サーバ処理時間を含まない |
| サーバ処理時間 | ② → 応答を返し始めるまで | サーバが要求を受けてから応答を返し始めるまでの時間。ネットワークレイテンシを含まない |
| TTFB(Time To First Byte) | ① → ③ | RTT+サーバ処理時間(新しく接続する場合は、接続時間も含む) |
| レスポンスタイム | ① → ④ | TTFB+応答データの転送時間。利用者が応答を受け取り終えるまでの時間 |
応答のデータ量が小さければTTFBとレスポンスタイムの差はわずかですが、ファイルのダウンロードのように応答が大きい処理では転送時間の分だけレスポンスタイムが長くなります。本稿におけるレスポンスタイムは、特に断りがない限り ① → ④ の時間を指すものとします。
🔍負荷ツールで測れる値と、負荷ツールの項目名との対応は H.負荷ツールの計測値と本稿の用語を参照
💡「レイテンシ」は文脈によって意味が変わる用語です。上表のネットワークレイテンシのほか、監視ツールや SRE の文脈ではレスポンスタイムとほぼ同じ意味で使われます。また、情報処理技術者試験などで教わる古典的な定義では、最初の応答が返り始めるまで(上表のTTFBにあたる)をレスポンスタイム、結果の出力がすべて終わるまでをターンアラウンドタイム(TAT)と呼び分けます。資料やツールに出てくる値が、どの区間を測ったものかを確認しましょう。
2-4.合格基準
2-3で処理パターンごとに設定した性能目標を、どのような条件・基準で満たせば合格とするかを、合格基準として定めます。性能目標は目指す値を示すもので、そのままでは判定に使えません。合格基準では、性能目標に次の点を加えます。
- どの集計値で判定するか(例:「2秒以内」を「95%tileが2秒以内」とする)
- 性能目標にはない判定条件(エラー率、タイムアウト、リソース使用率)
- 負荷の水準や処理の性質による違い(通常時とピーク時、目標を決めにくい処理)
- テストの種類ごとの判定の観点(2-1で決めたゴールによって変わる)
実際に計測を行ってはじめて合格基準が実態に即していないことに気づくことがあります(「非同期処理のレスポンスタイムが未設定だった」など)。結果に合わせて基準を歪める(単にレスポンスタイムを延ばす)のでなく、性能要求を踏まえ改めて合格基準全体を見直し・合意したうえで、各処理パターンの合格基準へ展開し、再判定します。基準を見直すときに誰と協議して決めるか、また基準を満たせなかった場合の扱い(改善して再計測するか、理由を付けて許容するか)も、あらかじめ決めておきましょう。
合格基準の例
| 指標 | 基準の設定方法 | 例 |
|---|---|---|
| レスポンスタイム | 2-3で処理パターンごとに定めた目標を、パーセンタイル値で判定する(E) | 詳細画面 200ms以下 検索・一覧画面 1500ms以下 ダウンロード 上限を定めない (いずれも通常時の95%tile) |
| スループット | 目標スループットを満たすか(E) | 打刻処理のスループットが12TPS以上(計測区間の平均) |
| エラー率 | 全体のエラー率の上限を設定する | 0.5%未満 |
| タイムアウト | 件数の上限を設定する | 0件 |
| リソース使用率 | ボトルネックとなっていないことの目安を設定する | CPU使用率の平均が70%以下 |
通常時とピーク時の基準
通常時・ピーク時のように性能目標が分かれる場合、合格基準を次のように設定することができます。
- ピーク時は基準を満たす割合を下げる(例:3秒以内を、通常時は95%、ピーク時は90%で満たす)
- ピーク時は許容する時間を延ばす(例:90%tileで、通常時は3秒以内、ピーク時は5秒以内)
前者は「ピーク時は一部の利用者が待たされても許容する」という業務上の合意を表しやすく、後者はパーセンタイルが揃うため通常時とピーク時の値を比べやすいという特徴があります。性能要求に応じ適切な基準を設定します。
目標を決めにくい処理の扱い
処理の性質や業務量の見込みによっては、目標を絶対値で決めにくいものもあります(ファイルのダウンロードのようにデータ量に比例して処理時間が伸びる処理、生成AIなど外部サービスの応答を待つ処理、業務量の見込みが立たずスループットの目標を決められない場合など)。こうした場合は、合格基準から一歩引いて、「●●秒を目標とする」あるいは「目標値を定めない」ことを関係者と合意しておきます。そのうえで、実測値をフィードバックし、改善方針を協議するといった方法があります。
テストの種類ごとの判定の観点
| テストの種類 | 判定の観点 |
|---|---|
| ロードテスト | 目標の負荷で、上表の基準を満たすか |
| 耐久テスト | 基準を満たすことに加え、実行の始めと終わりでレスポンスタイムが劣化していないか、メモリ使用量が増え続けていないか |
| スパイクテスト | 急増の間の劣化が許容範囲か、急増が収まった後に元の性能へ戻るか |
| キャパシティテスト・ストレステスト | 合否よりも、上限の値や限界を超えたときの振る舞いを把握することが目的。把握した値や振る舞いを記録する |
3.テスト計画
2章で定義した目的・性能目標・合格基準をもとに、実施するテストシナリオと、タスクやスケジュール・体制・役割分担・環境などを定義します。
3-1.テストシナリオの決定
2-3で設定した性能目標(通常時・ピーク時それぞれのユーザ数・スループット・レスポンス目標)を検証できるよう、次の項目を定めます。
| 検討項目 | 説明 |
|---|---|
| テストの種類と業務量 | 目的・ゴールを達成するために、1-1.性能テストの種類の中から実施する性能テストの種類を選び、それぞれをどの業務量(通常時・ピーク時など。2-3)で実施するかを大まかに決めます。 (例)通常時の業務量でロードテスト、ピーク時の業務量でロードテストとスパイクテスト、通常時の業務量で12時間の耐久テスト ロードテストを基本に、サービスの用途や提供先(社内・社外の不特定多数など)、運用保守体制、ユーザ数増加率、システム構成、将来のビジネスの見通しなどを勘案して、「いま」実施しなければならないテストを決定します。 |
| 業務シナリオの洗い出し | 性能テストで再現する業務シナリオを洗い出します。機能一覧や業務フローをもとに、代表的な業務や性能問題が想定される業務を挙げ、対象外とする業務はその理由を記録しておきます。 各業務シナリオの中身(画面の操作手順や送信頻度など)は5章で設計します。 |
| テストシナリオと負荷条件 | テストシナリオは複数の業務シナリオを組み合わせて負荷ツールに実装したものです。 各テストシナリオに掛ける仮想ユーザ数と、ランプアップ・計測区間・ランプダウンの時間などの負荷条件を定めます。 業務によって業務量のピークが異なる場合(月末に集中する締め処理など)は、そのピークを再現するテストシナリオを分けて設けます。 テストシナリオの具体的な中身(業務シナリオの構成や送信頻度)は5章で設計します。 |
| 実施回数 | 性能の計測値は同じ条件でも実行ごとにばらつくため、同じテストシナリオを同じ条件で複数回実施し、値が再現することを確認します。 途中でシステム構成・データ量・負荷条件などを変えると、値の違いが性能の差なのか条件の差なのか見分けられなくなります。比較したい計測どうしは同じ条件で実施する計画とし、条件を変える場合は変えた点を記録します。 |
テストシナリオの例
1-1のテストの種類は、負荷の掛け方が共通するものをまとめて、1つのテストシナリオとして実施することが多くあります。次に例を示します。
| テストシナリオ | 含むテストの種類 | 負荷の掛け方 | 主に確認すること |
|---|---|---|---|
| 1 | ロードテスト、ボリュームテスト、スケーラビリティテスト | 将来想定されるデータ量を投入し、通常時・ピーク時の業務量を段階的に掛ける。処理能力を拡縮する場合は、台数やスペックを変えて繰り返す | 性能目標を満たすか。データ量による劣化がないか。処理能力の拡縮が設定どおりに働くか |
| 2 | 耐久テスト | 通常時の業務量を長時間掛け続ける | 時間の経過とともにレスポンスタイムが劣化しないか。メモリ使用量などが増え続けないか |
| 3 | キャパシティテスト、スケーラビリティテスト | 負荷を段階的に積み増す。まずサーバ1台あたりの上限を求め、台数を増やして繰り返す | 性能目標を満たせる上限の値。台数を増やしたときに処理能力が伸びるか |
| 4 | スパイクテスト | 通常時の業務量でウォームアップを済ませた後、計測区間の途中で仮想ユーザ数を数倍〜数十倍に急増させ、短時間で元に戻す | 急増の最中にエラーや大きな遅れが出ないか。急増が収まった後に元の性能へ戻るか |
| 5 | ストレステスト | 上限を超える負荷を掛ける、またはリソースを減らした状態で負荷を掛ける | 限界を超えたときの振る舞い。負荷が収まった後に元の性能へ戻れるか |
| 6 | 並行実行テスト | 同じデータを多数の利用者が同時に更新する業務に絞って負荷を掛ける | ロック待ち・デッドロック・更新の競合によるエラーが起きないか |
3-2.体制・スケジュール・環境
| 検討項目 | 説明 |
|---|---|
| タスク分割 | 性能テストに必要なタスクを網羅的に洗い出します。 |
| スケジュール | スケジュールを引き、クリティカルパスを明らかにしましょう。 |
| 体制・役割分担 | テストに関わる関係者やそれぞれの役割を明らかにしましょう。チーム外・他部署・他社との役割分担を明らかにしましょう。 |
| 環境 | テストに用いる環境、構築方法、データ準備方法、共用環境の占有期間、所用コストなどを明らかにします。 テスト環境のスペック(サーバの性能・台数)、スケール設定、データ量は本番環境と揃えます。コストなどの事情で揃えられない場合は、差異を明記したうえで、計測結果をどこまで本番の性能とみなすかを事前に決めておきます。差異が残ったままの計測値は、本番の性能を表すとはいえません。 |
4.負荷ツール選定
テストシナリオを実装する負荷ツールを選定します。負荷ツールで実現できること(待機時間の設定方法、オープンモデルを使えるかなど)はテストシナリオの作成にも影響するため、テストシナリオの作成に先立って選定しておきましょう。
負荷ツールの役割はユーザ端末(複数)を模してサーバへ要求を送信することです。負荷ツールに求められる要件は性能テストの目的によって異なります。性能目標・テストシナリオ・ワークロード等を踏まえ必要な機能・性能要件を備える負荷ツールを選定しましょう。
負荷ツールの例
- シンプルなHTTP負荷ツール
- ab(Apache Bench)
- Vegeta(Go)
- 複雑なシナリオを記述できる負荷ツール
- JMeter(Javaアプリケーション上でシナリオを作成し JMXファイルとして保存する)
- Locust(Pythonでシナリオを記述できる)
- k6(JavaScriptでシナリオを記述できる)
- Gatling(Scalaでシナリオを記述できる)
- Playwright(API でなくブラウザベースのシナリオを記述できる。ただし重い)
- 有償の負荷ツール
- OpenText LoadRunner(旧 Micro Focus・HP)
- パブリッククラウドが提供する分散ロードテスティングサービス
-
Azure App Testing(Playwright シナリオなどもサポートされています)
- Azure Load Testing(Azure App Testing の一部。JMeter・Locust によるシナリオがサポートされています)
- Distributed Load Testing on AWS(JMeter・Locust ・k6 によるシナリオがサポートされています)
-
Azure App Testing(Playwright シナリオなどもサポートされています)
負荷ツール選定のポイント
- 必要な負荷をかけられる
- 必要な数の仮想端末を同時に起動できる
- 複数プロセス/スレッドで連携して負荷を掛ける
- 複数ノードから負荷を掛けられる
- 開始時にいきなり最大負荷とならないよう設定時間内で徐々に負荷を上げられる(ランプアップ)
- 分散ロードテスティングに対応できる(シナリオファイルがそのまま使える)
- 1ノードあたりで生成できる負荷の上限が分かり、負荷生成側のCPU・メモリの使用状況を監視できる
- シナリオを作成し実行できる
- 指定回数実行・タイマー・繰り返し実行などのフロー制御
- 要求内容を動的に生成できる
- 要求内容をCSV 等のファイルから読み取れる
- セッションを維持する
- 様々なプロトコル(HTTP/S、MQTT、 TCP、UDP)に対応できる
- 管理
- 負荷送信先のサーバ等を環境変数・設定ファイル等で簡単に切り替えられる
- 費用・制約
- 課金体系(仮想ユーザ数 × 実行時間など)が、予定している負荷条件と実施回数に見合う
- 1回のテストの実行時間や仮想ユーザ数の上限が、予定しているテスト(長時間の耐久テストなど)に足りる
- 実行結果の記録・分析
- 処理時間や応答内容をCSV等のファイルに保存できる
- 統計値を出力できる
- ランプアップ期間や終了間際の期間等を分析対象から除外できる
- スループットやレスポンスタイムの推移をグラフ等に出力できる
💡APIベースでなく、Playwright などを用いたブラウザベースの負荷テストでも、本概論の考え方はそのまま使えます。ただし、1仮想ユーザあたりの負荷生成の負担が大きく、大量の負荷は掛けにくいため、負荷はAPIベースのツールで掛け、画面の体感レスポンスは少数のブラウザで計測する組み合わせがよく用いられます。
5.テストシナリオ作成
実業務でサーバが受ける負荷をワークロード(Workload;負荷)といいます。ワークロードは出来るだけ実業務と同様にする必要があります。ワークロードは要求の送信順や呼び出しの割合、時間あたりの送信頻度などの組み合わせによって構成されます。
本章では、本番相当のワークロードを再現するテストシナリオを作成します。テストシナリオは次の要素で構成されます。
| 要素 | 内容 | JMeter での対応(例) |
|---|---|---|
| テストシナリオ | テストの目的(3-1)に応じて業務シナリオを組み合わせ、負荷条件を定めたもの | テスト計画(.jmx ファイル) |
| 業務シナリオ | 業務フローやユーザストーリーから抽出した一連の画面操作 | スレッドグループ |
| 機能 | 業務シナリオを構成する個々の要求(API) | サンプラー(HTTPリクエストなど) |
業務シナリオはそれぞれ独立したスレッドグループなどとし、テストシナリオの目的に応じて有効・無効を切り替えられるように作りましょう。複数のテストシナリオを1本のシナリオファイル(JMeter の .jmx ファイルなど)にまとめ、業務シナリオの有効・無効で切り替えられるのが理想です。
本章の成果物は、テストシナリオ(負荷ツールのシナリオファイル)と、利用割合や送信頻度などを推定した論拠(前提条件・想定値・計算式など)の記録です。あわせて、計測結果を分析するための準備も行います。
5-1.本番相当のワークロード
a) 本番相当のワークロードとは
例えば性能テストで毎回同一画面・同一パラメータで高負荷を掛け目標スループットが達成できたとして、これは十分な検証といえるでしょうか。実運用におけるアクセスパターンは複数画面の組み合わせであり、他画面側に別の負荷要因が存在することが考えられます。毎回同一パラメータというのはどうでしょうか。こうした場合、DBキャッシュ等の効果で見かけ上良い数値が出るものの、I/O負荷が考慮されていないため実業務に耐えられないといった懸念があります。いざ本番を開始したら、検証時より高い負荷が掛かりサーバダウンに見舞われる、といったことになりかねません。本番で実際に想定されるワークロード相当で負荷を掛けることによって、本当のシステムの性能特性を把握することができるのです。
b) 業務シナリオの組み立て
ワークロードの内容によって負荷が掛かるコンポーネントは大きく異なります。CPU、メモリSwap/FullGC、ディスクI/O、Quota/Burstクレジット消尽、NW帯域/ネットワークレイテンシ、CDNキャッシュヒット/オリジン要求発生、DBキャッシュヒット/IOアクセス発生、Leaderノードボトルネック・・・。システムの各コンポーネントに本番相当の負荷を与えるワークロードの再現を目指しましょう。
業務シナリオは、3-1で洗い出した業務(実際の運用シーンで想定される代表的な業務、性能問題が想定される業務)について、業務フローやユーザストーリーから画面操作の流れを抽出して組み立てます。そのうえで、各機能の利用割合や要求送信頻度などを推定し本番相当のワークロードを作り込んでいきます。運用実績があるシステムであればアクセスログを元に推測できるかもしれません。そういったものが利用できない場合、例えばショッピングサイトであれば想定CVRなどの手がかりを元にアクセス頻度を推定します。いわゆるフェルミ推定であり厳密な正確さを求めるものではありませんが、仮説の論拠が説明可能であること、論拠の見直しに応じてシナリオに反映できることが大切です。前提条件・想定値・計算式などの論拠を記録しておきましょう。
- 業務シナリオの設計(要求割合や送信頻度)
- 一般サイトであればユーザの回遊パターンやCVRなど
- 業務システムであれば業務フローから推測される画面操作手順
- 画面操作間に挟み込む待機時間など
- 実行条件等の設計(実負荷の再現精度を高める)
- 事前投入するデータ件数やカーディナリティ、データ間の紐付け
- 検索条件(前方一致など)のスキャン範囲(Optimizer Cost)やヒット件数(Pagination)
- CDNキャッシュヒット率(静的コンテンツ配信の場合)
- 画面結果キャッシュ率(動的コンテンツの場合)
- データベースバッファキャッシュ率(動的コンテンツの場合)
5-2.利用者の操作の再現
業務シナリオをそのまま負荷ツールのシナリオにすると、シナリオ内のすべての操作が1周に1回ずつ実行されます。実際の利用では、すべての利用者がすべての画面を開くわけではありません。操作ごとの出現頻度が実態と合っていないと、各機能の利用割合が本番と大きく異なってしまいます。
a) 画面遷移の深さ
一覧画面を開いた利用者が全員、詳細画面やさらにその先の画面まで進むわけではありません。画面遷移が深くなるほど、到達する利用者は減っていきます。画面ごとに到達する利用者の割合(例:一覧 100%、詳細 50%、明細 25%)を想定し、シナリオに反映しましょう。
深い画面ほど割合が小さくなるように設定し、浅い画面を通らずに深い画面だけが実行されることがないようにします。また、画面操作間の待機時間は、その画面へ遷移する操作とセットで扱います。遷移しない利用者には、待機時間も発生しないようにしましょう。
b) 頻度の低い操作
月に数回しか行われない操作(設定変更、一括ダウンロードなど)をシナリオで毎回実行すると、その操作だけ実態の数十倍の負荷が掛かります。頻度の低い操作は、次のいずれかで扱います。
| 扱い方 | 用いる場面 |
|---|---|
| シナリオに含めるが、通常は無効にしておく | 計測できる状態を保ちつつ、通常の負荷には含めない。単体で測りたいときに有効にする |
| 別のシナリオに分ける | その操作だけを対象に負荷を測りたいとき |
| シナリオに含めない | 負荷への影響が無視できるとき |
c) クローズドモデルとオープンモデル
負荷の掛け方には、仮想ユーザ数を固定して負荷を掛ける方式(クローズドモデル)と、要求が届く頻度(件/秒)を固定して負荷を掛ける方式(オープンモデル)があります。クローズドモデルでは、サーバの応答が遅くなると仮想ユーザが応答を待つため、送信頻度も自然に下がります。オープンモデルでは応答の遅れにかかわらず要求が届き続けます。
どちらを用いるかは、システムの利用者数の特徴によって決まります。
- 社内システムや会員数の限られたサービスのように、利用者数の上限を規定しやすいシステムでは、クローズドモデルで想定する仮想ユーザ数を掛け、性能目標を満たせるかを確認します。
- 不特定多数の個人が利用するWebサービス(コンシューマ向けサービス)のように、利用者の母数が100万人、1,000万人を超えるシステムでは、全ての利用者を再現することはできず、スケーラビリティがより重要になります。まずキャパシティテストでサーバ1台あたりの処理能力を測り、次にオープンモデルで負荷を上げていっても、スケールアウトによって性能が安定して拡張でき、性能目標を満たせることを確認します。
5-3.シナリオの実装
a) 業務シナリオの作成
業務シナリオの画面操作を、負荷ツールのシナリオとして作り込みます。本番相当の負荷とするため、次の点に注意しましょう。
| 観点 | 内容 | JMeter での例 |
|---|---|---|
| 要求内容のパラメータ化 | ユーザ・検索条件・登録内容などを外部ファイルから読み込み、仮想ユーザごと・繰り返しごとに変える。同一パラメータでは、DBキャッシュ等の効果で見かけ上良い数値が出てしまう(5-1 a)) | CSV Data Set Config |
| 応答からの値の受け渡し | 応答に含まれるIDやアクセストークンなどを取り出し、後続の要求に引き継ぐ。固定の値を送り続けると、エラーになったり、全員が同じデータを参照したりする | JSON Extractor、Regular Expression Extractor |
| 応答内容の検証 | ステータスコードが正常でも、エラーメッセージや空の結果が返っていることがある。主要な要求には応答内容の検証を入れ、エラーとして数えられるようにする | Response Assertion、JSON Assertion |
| 画面の表示に伴う要求 | 1画面の表示で呼ばれる複数のAPI、CORSのプリフライト要求、定期的な状態確認(ポーリング)なども、画面と同じように送る。要求は画面操作ごとにまとめ、画面単位の時間も計測できるようにしておく(2-4) | Transaction Controller |
| 待機時間(思考時間) | 画面操作の間に、利用者が画面を読む・入力する時間を待機として入れる。想定値とその論拠を記録しておく(5-1 b))。画面へ遷移しない利用者には、待機も発生させない(5-2 a)) | Constant Timer、Uniform Random Timer |
| 対象外の要求の除外 | 外部の解析タグや広告、CDNから配信する静的ファイルなど、テストの対象外のサーバへの要求は除く | 埋め込みリソースの取得(URLの絞り込み) |
| 接続先・負荷条件の外部指定 | 接続先のサーバ、仮想ユーザ数、実行時間などはパラメータで外から指定し、シナリオを書き換えずに環境や負荷条件を切り替えられるようにする |
${__P(host)} と起動時の -J オプション |
シナリオは、開発環境などで業務シナリオごとに1ユーザずつ動かしながら作り込みます。
💡シナリオの作成方法としては、ブラウザの操作を負荷ツールのHTTPプロキシ機能で記録してパラメータ化する、画面操作のテストシナリオ(Playwright など)を変換する、API定義(OpenAPI など)からAIエージェントで作成する、などの方法があります。
b) テストシナリオの時間配分
5-1・5-2で決めるのは「どのような負荷を掛けるか」(業務シナリオの構成・要求の割合・送信頻度)です。シナリオの実装では、それを「1回の実行の中でどう時間配分して流すか」を決めます。3-1で大まかに定めた時間配分をもとに、1回の実行を次の区間で構成します。
| 区間 | 内容 |
|---|---|
| ランプアップ | 仮想ユーザを徐々に起動し、目標の負荷まで上げていく区間 |
| 計測区間 | 目標の負荷が一定に続く区間(定常状態、steady state)のうち、分析の対象とする区間 |
| ランプダウン | 仮想ユーザが処理を終えて抜けていく区間 |
立ち上がり直後はキャッシュが空で、DBや外部APIへの接続もまだ確立されていないため、同じ負荷でも定常時より遅い値が出ます(コールドスタート)。オートスケールを使う環境では、台数が負荷に追いつくまでの時間もかかります。これらの影響が計測区間に入らないよう、目標の負荷に達した後も負荷を掛けたまま慣らす時間(ウォームアップ)を置いてから計測区間とし、計測区間は分析に必要なサンプル数が得られる長さにしましょう。
すべての仮想ユーザがほぼ同時にシナリオを開始すると、画面操作と待機のタイミングが揃い、要求数が山と谷を繰り返します。計測区間の負荷を一定に保つには、仮想ユーザごとに開始時刻をずらす(最初の操作の前にランダムな待機を入れるなど)とよいでしょう。ランプアップも開始時刻をずらす仕組みですが、待機時間が長いシナリオでは、ランプアップだけでは開始時刻が十分にばらつかないことがあります。
c) 仮想ユーザ数の設定
本番相当のワークロード(5-1)を再現するためには、要求の合間に適度に待機(思考時間)を設けます。待機(思考時間)を含むシナリオでは、本番環境における「ログイン中のユーザ数」と、負荷ツールに設定する「仮想ユーザ数」(JMeter ではスレッド数の合計)は同じ値となります。仮想ユーザ1つ1つは本番環境における利用者1人1人として振る舞います。ユーザ数・処理中のリクエスト数・スループットの関係は、Fを参照してください。
| 性能要求の示し方 | 仮想ユーザ数の求め方 | 例 |
|---|---|---|
| ログイン中のユーザ数 | そのまま用いる | 通常時 300人 |
| 目標スループット | 目標スループット × 業務シナリオ1周の所要時間 ÷ 1周あたりの要求数 | 目標10TPS、1周あたり要求20件・所要600秒(1件あたり応答1秒+思考時間29秒)の場合、10TPS × 600秒 ÷ 20件 = 300人 |
実行後は、実績のスループットが目標に届いているかを確認し、届かない場合は待機時間の想定や仮想ユーザ数を見直しましょう。
仮想ユーザ数は、業務シナリオごとにパラメータで外から指定できるようにしておき(a))、テストシナリオごとに変えて実施します(3-1)。業務シナリオごとの値は、利用割合(5-1 b))に応じて割り振ります。
テスト計画や結果レポートに「〇〇人」と書くときは、どの数を指しているのかを明記しましょう。
💡待機を入れず要求を連続して送るシナリオでは、仮想ユーザ数は処理中のリクエスト数にほぼ等しくなります。一定の件数の要求を絶え間なく受けたときに耐えられるかを確かめる場合に用います。
💡オープンモデルを用いるケース
アクセス数の急増に対するスケーラビリティ・エラー率などを確認する場合、クローズドモデルでは応答が遅くなると仮想ユーザが応答を待つため1周の所要時間が伸び、同じ仮想ユーザ数でもスループットが下がり目標負荷に達しないことがあります。このようなケースでは、応答の遅れにかかわらず要求が届き続けるオープンモデル(5-2 c))でテストシナリオを構築します。到着頻度の求め方はGを参照してください。
d) 動作確認
作り込んだ業務シナリオを組み合わせたテストシナリオを動かし、業務シナリオとしての一連の動作が意図どおりに行われるかを確認します。画面操作の順序、応答からの値の引き継ぎ、画面ごとの到達割合(5-2 a))や待機時間などが、設計したとおりになっているかを確かめましょう。ここでは業務シナリオとしての一連の動作の確認を目的とし、計測に向けて環境・データが揃っているかについてはスモークテスト(8-1)で実施します。
e) 補足:スパイクテスト用のシナリオ
スパイクテストを行う場合は、計測区間の途中で仮想ユーザ数を急増させられるよう、急増させる仮想ユーザ数と開始時刻をパラメータで指定できるシナリオにしておきましょう(JMeter であれば、急増分を別のスレッドグループとし、スレッド数と起動の遅延をプロパティで外部から指定するなど)。本番では最低台数のサーバが常に稼働しており、急増は温まった状態で起きるためです。
5-4.カバレッジの点検
シナリオを作成したら、3-1で洗い出した業務シナリオのとおりに作れているかを確認します。システムが提供するAPIの一覧(API仕様書など)と、シナリオが実際に呼び出す処理を突き合わせ、漏れがないかを確かめましょう。API仕様書に定義が残っていても画面からは呼ばれなくなった処理もあるため、画面側の呼び出しとも照合するとよいでしょう。業務上重要な機能、性能上懸念のある機能を対象から取りこぼしていないかも点検しましょう。
5-5.分析の準備
負荷ツールでは、要求ごとに次の項目を記録するよう設定しておきます。負荷ツールの項目名との対応は🔍Hを参照してください。
| 計測項目 | 説明 | 例 |
|---|---|---|
| 開始時間 | 送信を開始した絶対時刻。ミリ秒精度。必要であればマイクロ秒精度 | 2020/01/01 10:00:00.000 |
| 経過時間 | 処理にかかった相対時間。ミリ秒精度。必要であればマイクロ秒精度 | 710 [ms] |
| 処理の種類 | URLパスなど。 | /login |
| 処理結果 | エラーの有無など。 | 200 |
| TTFB | 応答の最初の1バイトを受け取るまでの時間(JMeter では Latency)。レスポンスタイムとの差から、応答データの転送時間を把握する | 650 [ms] |
| 接続時間 | サーバとの接続を確立するまでの時間(JMeter では Connect。TLSハンドシェイクの時間を含む)。通常は接続を使い回すため、この値が0でない状況が頻発する場合は意図しないTCPタイムアウト等によるTLSハンドシェイクが繰り返されていないかを確認する。思考時間がサーバ側の keep-alive のタイムアウト(Node.js の既定は5秒など)より長い場合は、要求のたびに接続し直すのは正常な動きである | 15 [ms] |
| 実行中の仮想ユーザ数 | その時点で動いている仮想ユーザ数(JMeter では allThreads)。計測区間で目標の仮想ユーザ数に達しているかを確認する | 300 |
| 待機時間 | 複数の要求をまとめて計測する場合の、要求と要求の間の時間(JMeter では IdleTime)。意図したタイマー以上に伸びている場合は、負荷ツール側の処理の遅れ(CPU不足やGCなど)が疑われる | 0 [ms] |
性能テスト実施後は9-1.計測結果の集計、E.性能メトリクスの集計方法についてに記載の結果分析を行います。負荷ツール付属の分析ツールがあればまずそれを使ってみましょう。必要であれば分析ツールを作成します。作成には Excel、Python、R などのお好みのツールを使用します。
6.環境構築
性能テストに用いる環境を準備します。サービスイン前の本番環境を用いる、本番同等の負荷テスト環境を構築する、共用環境を占有するなどによってテスト環境を確保します。計測結果が本番の性能を表すよう、環境は出来るだけ本番相当にしましょう。
6-1.本番相当の構成
テスト環境のスペック(サーバの性能・台数)や設定は、本番環境と揃えます(3-2)。スペックや台数に比べて、次のような設定は見落とされやすいので注意しましょう。
- アプリケーションの設定(DBの接続プールのサイズ、スレッド数、タイムアウトなど)
- ログの出力レベル(オンプレではデバッグログを大量に出力していると、それだけで処理が遅くなる。クラウドでは処理への影響はオンプレより小さいことが多いものの、ログの取り込み量に応じた費用がかさむ)
- 前段の構成(CDN、キャッシュ、WAF、APIゲートウェイなど)
- ネットワークの経路(リージョン、負荷ツールからサーバまでの経路)
負荷ツールを動かすマシンの性能・台数にも余裕を持たせます。負荷ツール側が先に限界に達すると、サーバの性能ではなく負荷ツールの性能を測ることになってしまいます。負荷ツールの稼働状況(CPU・メモリ使用率など)も評価の対象に含めましょう。負荷ツール側がボトルネックになっていた場合、そもそも計測値の信頼性が低くなります。
データ量は7章で揃えます。揃えられない差異は、3-2で決めた扱いに沿って記録し、結果まとめ(10章)にも明記しましょう。
6-2.スケール設定
クラウドでは、負荷に応じてサーバの台数を自動で増減させる仕組み(オートスケール)を使うことが多くあります。性能テストでは、最小・最大台数、スケールの条件(CPU使用率や処理中のリクエスト数など)、スケール後に次の判定までおく待機時間(クールダウン)を本番と同じ設定にします。設定が違うと同じ負荷でも台数が変わり、計測値は本番の性能を表しません。
オートスケールでは、新しいインスタンスが起動するまでの間に、一時的にレスポンスタイムが悪化したりエラーが発生したりすることがあります。結果を分析する際はインスタンス数の推移と突き合わせ、劣化がスケール中の一時的なものか、継続するものかを見分けましょう。急な負荷増にスケールが追従できるかを確かめたい場合は、スパイクテスト(1-1)として扱います。
スケールインでは、処理中のままインスタンスが停止されます。アプリケーションが停止の通知(SIGTERM など)を受けたときに、新しい要求の受け付けを止め、処理中の要求を終えてから停止する仕組み(Graceful Shutdown)に対応していないと、処理中の要求がエラーになってしまいます。停止までの猶予時間が、処理時間の長い要求より短くないかもあわせて確認しましょう。ランプダウン中のエラーは計測区間の外になりますが、見逃さずにスケールインの時刻と突き合わせて確認しましょう(9-3 a))。
6-3.無風状態と外部サービス
テスト実施時は負荷テスト以外のアクセスが発生しないよう、いわゆる「無風状態」とします。性能テスト以外のアクセスが計測結果に含まれてしまうと計測結果の信頼性が揺らいでしまいますし、パフォーマンスの比較やボトルネックの分析も困難となります。
性能テスト環境は自システム環境では完結せず外部呼び出しが含まれることもあります。その場合外部システムに協力をお願いしたり、それが難しい場合はスタブを作成するなどの準備が必要となります。外部サービス(生成AIのAPIや外部の認証基盤など)には、単位時間あたりの呼び出し上限(クォータ)や従量課金があることが多く、負荷テストで上限に達したり想定外の費用が発生したりします。事前に上限と費用を確認し、必要であれば上限の引き上げを申請するか、スタブで代替しましょう。
6-4.認証の扱い
ログインが必要なシステムでは、負荷ツールからの要求に認証情報(アクセストークンなど)を付与する必要があります。性能テストでは、認証を本番とは別の経路とすることも多くあります。仮想ユーザの数だけ本番と同じ認証を通すのは、次のような理由で難しいためです。
- OIDC などの認証は、ブラウザでの HTTP リダイレクトを前提としており、API の呼び出しだけでは認証処理を完結できない
- 外部の認証基盤(IDaaS)ではテスト目的で負荷を掛けることが禁止されている場合がある。多要素認証や呼び出し回数の上限があり、大量のログインを短時間に行えない
- 呼び出し回数に応じた費用がかさむ
- 長時間の耐久テストでは、テストの途中でトークンの有効期限が切れる
別の経路とする場合は、インフラ側に専用の経路を設ける必要があります。環境構築の段階で準備しておきましょう。
主な対応方法は次のとおりです。
| 対応方法 | 内容 | 注意点 |
|---|---|---|
| 認証の検証を省略する経路を用意する | テスト環境に、認証の検証を行わない専用の経路を用意する | 送信元IPアドレスの制限などで、テスト以外からのアクセスを防ぐ。認証処理そのものの性能は測れないため、必要なら別に測る |
| 事前にトークンを発行しておく | テスト前にトークンをまとめて発行し、ファイルから読み込ませる | 有効期限内にテストを終える必要がある |
| シナリオ内で認証する | ログインとトークンの再取得をシナリオに組み込む | 認証基盤にも負荷が掛かるため、事前に認証基盤の上限や利用規約を確認する |
6-5.構成変更への備え
環境構築は初期段階の準備をもって完了とは限りません。クラスタノード追加時の性能向上を確認したい場合は計測の区切りごとのシステム構成変更・リセットに備え環境構築ツールの利用を検討した方が良いでしょう。この際データストアを構成するノードも構成変更対象に含まれている場合はテスト用データのバックアップ・リストアについても併せて検討が必要です。
6-6.性能メトリクスの取得
負荷ツールの記録に加えて、サーバ側の性能メトリクスを取得できるよう、監視の設定を済ませておきます。アプリケーション・データベース・APIゲートウェイなどコンポーネントごとに取得対象を決め、粒度を揃え、スケールアウト・スケールインの挙動も確認できるよう計測区間の前後も含めて取得します。元データは、後から時刻を突き合わせられるよう保存しておきましょう。
a) オンプレミスの場合(H/W・OS等計測メトリクス)
| ソースタイプ | メトリクス | 説明 | コマンド例 |
|---|---|---|---|
| CPU | CPU使用率 | CPUを有効に使えている割合。 | top |
| ロードアベレージ | 実行中・実行待ち・I/O待ちのプロセス数の平均。 | top | |
| コンテキストスイッチ | I/O待ちやスレッドの切り替えで発生するコンテキストスイッチの数。 | vmstat | |
| メモリ | メモリ使用量/空きメモリ | 物理メモリ使用状況。 | vmstat/free |
| スワップ使用量 | 物理メモリからディスクに退避された量。 | vmstat/free | |
| スワップアウト/スワップイン回数 | スワップ発生回数。ディスクはメモリと比べ3~4桁遅いためスワップは極力回避すること。 | vmstat | |
| ディスク | 秒間ディスク帯域 | ディスク転送量を把握する。 | iostat |
| 秒間I/O回数 | ディスクI/O回数を把握する。IOPSスケールアップのための目安となる。 | iostat | |
| I/Oキュー長 | ディスクI/Oスケールアップのための目安となる。 | iostat |
b) クラウドの場合(クラウドサービス・ミドルウェアのメトリクス)
コンテナやマネージドデータベースのように OS に入れない環境では、a) のコマンドは使えません。クラウドの監視サービス(Azure Monitor、Amazon CloudWatch など)が提供するメトリクスを取得して代用します。
| ソースタイプ | メトリクス | 説明 |
|---|---|---|
| アプリケーション(コンテナ・PaaS) | CPU使用率・メモリ使用率 | 最大値と平均値の両方を記録する。平均値だけでは一時的なスパイクが見えない |
| インスタンス(レプリカ)数 | スケールした時刻を把握し、レスポンスタイムの悪化やエラーの発生時刻と突き合わせる | |
| HTTPステータス別のリクエスト数 | サーバに届いた要求の数とエラー(5xx)の発生時刻・件数。負荷ツール側の送信数との差から取りこぼしも分かる | |
| サーバ処理時間 | 2-3 c)のサーバ処理時間。レスポンスタイムとの差から遅れの原因を切り分ける | |
| データベース | CPU使用率・メモリ使用率 | DB がボトルネックになっていないかを見る |
| 接続数・接続失敗数 | 最大接続数に対する余裕と、接続の失敗の有無 | |
| ロック待ち | 更新の競合による待ちの有無 | |
| スロークエリ | 実行時間の長いSQLを特定する | |
| APIゲートウェイ・ロードバランサー | リクエスト数・応答時間・エラー数 | 前段での遅延や、流量制御による拒否の有無 |
メトリクスは収集の粒度(1分ごとなど)で平均化されるため、粒度が粗いと短時間のスパイクが見えなくなります。粒度は計測前に決めておきましょう。1つの要求がどのコンポーネントで時間を使ったかを追うには、APM(アプリケーション性能監視)や分散トレースも有効です。
7.データ準備
環境だけでなくデータの準備も必要です。ストレージやデータベース上の大量データは処理効率・処理時間に影響を及ぼすことが多く、実業務で想定されるデータ蓄積件数を再現しておく必要があります。データ件数・量によって作成・転送・展開に長時間を要することがあります。データ作成ツールの作成も視野に入れながら期間に余裕をもって準備を進めましょう。
7-1.大量テストデータの準備
外部サービスや生成AIの処理結果のように、SQLなどで直接作り出せないデータがあります。一方で、実処理だけで大量のデータを用意するのは、時間や費用の面で難しいことがほとんどです。そこで、まず実処理で複製元データを作成し、その複製元データをSQLなどで大量に複製して件数を増やします。複製元データの作成には時間がかかることが多いため、早めに準備しましょう。
7-2.テスト用アカウントの割り当て
テスト用のアカウントは、1つの仮想ユーザに1つずつ割り当てます。1つのアカウントを複数の仮想ユーザで使い回すと、一方のログアウトで他方のセッションが切れる、多重ログインの制限にかかるなど、実際の利用では起きない動きになります。アカウントの数が仮想ユーザ数に足りているかを、実行前に確認しましょう。
7-3.テストで消費・変化するデータ
登録・削除・状態の更新を行う処理では、テストを実行するたびにデータが消費されたり状態が変わったりします(一度処理したデータは、次の実行では処理の対象にならないなど)。実施回数分のデータを用意するか、テストシナリオの実施ごとにデータを作り直します。どのデータを実施ごとに戻し、どのデータを使い回すのかを決めておきましょう。
7-4.データの競合
複数の仮想ユーザが同じデータを同時に更新すると、実際の利用では起きない競合(楽観ロックによる更新エラーなど)が発生し、計測結果にエラーが混ざります。実際の業務で同時に更新されることのないデータは、仮想ユーザごとに別のデータを割り当てて競合を避けます。同時更新が業務で起こり得る場合は、並行実行テスト(1-1)として扱います。
7-5.後片付け
テストで投入・生成したデータを削除する手順も、あわせて準備します。テストデータが残ったままだと、次のテストのデータ量や結果に影響します。
8.性能テスト実施
さて、いよいよ負荷ツールからサーバに対し負荷を掛けていきます。
8-1.スモークテスト
本番の計測を始める前に、環境・データ・シナリオを用意した状態でシナリオを実行し、計測に向けて環境・データが整っているかを確認します(スモークテスト)。いきなり送信頻度全開とはいきませんが、仮想ユーザ数を絞る、実行時間を短くするなど制限付きでいいので、次の点を確認しておきましょう。
- すべての業務シナリオがエラーなく最後まで実行できること
- 計測の対象環境に接続でき、負荷ツールから想定どおりに要求が届くこと(疎通確認。接続先の切り替えや認証の経路(6-4)が正しく働いているか)
- 準備したデータで実行できること(アカウントの割り当て、消費されるデータ、データの競合。7章)
- 計測結果が記録され、集計・分析できること(5-5)
8-2.テストシナリオの実施
スモークテストが終わったら、3-1で決めたテストシナリオを順に実施し、実施ごとに計測結果を分析・評価します(9章)。基本となるロードテストから始め、目標を満たせることを確認してから、他のテストシナリオへ進みましょう。
いずれのテストシナリオでも、次の点に注意して進めます。
- 負荷は低めから段階的に上げていきましょう(例:通常時の業務量、ついでピーク時の業務量)。
- 計測中はエラー・システムリソース・ボトルネック有無を監視し、計測が終了したら結果を分析します。集計は、計測結果のうち計測区間を対象に実施します(9-1)。
- 目標性能をクリアした時点で、そのテストシナリオの検証は完了です。目標達成後、尚も負荷を積み増して計測を継続する場合、検証目的にキャパシティテストやストレステストの観点が混じっている、あるいは検証目的がすり替わっている可能性があります。改めて目的を確認してみましょう。
- 負荷を積み増して上限を探す場合(キャパシティテストなど)は、実績スループット・レスポンスタイムをグラフにプロットしながら進め、スループットが頭打ちになるポイント、レスポンスタイムが許容値を超えて悪化するポイントなどを分析します。
8-3.計測結果の記録
実施のたびに、負荷ツールの記録(5-5)と性能メトリクス(6-6)を保存し、あわせて計測条件を記録します。
計測値は、計測条件とあわせて記録しなければ正しく評価できません。計測ごとに次の条件を記録します。条件が異なる計測どうしは比較できません(3-1)。
| 項目 | 記録する内容 | 例 |
|---|---|---|
| システム構成 | 各サーバ・サービスのスペック、台数、主な設定値 | APサーバ 2vCPU/4GB × 2台、DB 4vCPU/16GB |
| スケール設定 | オートスケールの最小・最大台数、スケールの条件 | 最小2台・最大10台、CPU使用率70% |
| データ量 | 主要なテーブルの件数、ファイル数 | 顧客10万件、注文100万件 |
| 負荷条件 | 仮想ユーザ数、ランプアップ時間、実行時間、シナリオの版 | 300仮想ユーザ、ランプアップ5分、30分 |
| 負荷ツール | ツールの名称と版、負荷生成ノード数 | JMeter 5.6、2ノード |
| 実施日時 | 開始・終了の時刻と、計測区間の範囲 | 2020/01/01 10:00〜10:30(計測区間 10:10〜10:25) |
8-4.エラー・ボトルネックの確認
検証中はエラーやボトルネックの有無をこまめにチェックしてください。テストシナリオの作り込み不足やサーバ処理の不具合などが原因であれば修正が必要です。性能目標を大きく超えたスループットのみで発生する場合は一定以上のスループットが流入しないよう流量制御を行うといった対策が考えられます。なお、エラー率は応答時間とは別の指標として集計し、合否を判定します。レスポンスタイムを集計する際は、エラー応答を含めるか除くかを明示してください。エラー応答は正常応答より極端に速い(即座に返るHTTP 500など)か極端に遅い(タイムアウト)ことが多く、区別せずに混ぜると応答時間の値がゆがみます。エラー・ボトルネック確認にあたっては下記項目をチェックします。
- 負荷ツールのログにエラーが記録されていないこと。
- アプリケーションログ・サーバログ等にエラーが記録されていないこと。
- H/W・OS等計測メトリクス、クラウドサービス・ミドルウェアのメトリクスにボトルネックとなる値が記録されていないこと。
- 負荷生成側(負荷ツールを動かすマシン)のCPU・メモリ・ネットワークに余裕があること。負荷生成側が飽和すると要求を予定どおり送れず、レスポンスタイムも実際より長く記録されます。
9.評価・改善
計測結果を分析し、性能目標に満たない場合はボトルネックを特定して改善したうえで、再テストを実施します。
計測結果は、負荷ツールの記録(5-5)と性能メトリクス(6-6)をもとに分析します。
性能テストはユーザ視点であるべきなので、スループットおよびレスポンスタイムは負荷ツールの記録から集計します。レスポンスタイムの集計は一般に%ile(パーセンタイル)を用います。サーバ側の処理時間に疑義があるときは、ネットワークレイテンシ等を排除した真の処理時間を性能メトリクスで参照するとよいでしょう。
一方で、スロークエリ、エラー・WARNログ、サーバのCPU・メモリ使用率、スケールアウト・スケールインの状況などは、サーバ側の性能メトリクスが主体になります。
9-1.計測結果の集計
計測結果のうち計測区間(5-3 b))を対象に集計します。ランプアップ・ウォームアップ中とランプダウン中は目標の負荷に達していないため、これらを集計に含めてしまうとスループットは実際より低く、レスポンスタイムはウォームアップ中は遅い・ランプダウン中は速いなど統計上のノイズとなってしまいます。下表の「計測期間」は、この計測区間を指します。集計例は、2-4の合格基準の例に対応させています。
| 集計項目 | 使用パラメータ | 導出方法 | 集計例 |
|---|---|---|---|
| スループット(秒毎) | 開始時間 | 秒ごとに計測結果を集計する。 (開始時間よりミリ秒以下を切り捨て、同一秒の行数を計数する) グラフによる分析(9-3 a))に用いる |
10:00:00 13TPS 10:00:01 12TPS |
| スループット(全体) | 開始時間、処理の種類 | 処理の種類ごとに、計測期間の総件数を計測期間の秒数で割った値(平均)とする。 スループット(秒毎)のうち最も高い値は、ピークスループットとして別に記録する |
打刻処理 12.6TPS(ピーク時、計測区間の平均) ピークスループット 19TPS |
| レスポンスタイム(秒毎) | 経過時間 | 秒ごとに経過時間を集計する。 グラフによる分析に用いる。 🔍集計方法はEを参照 |
10:00:00 710ms 10:00:01 695ms |
| レスポンスタイム(全体) | 経過時間、処理の種類 | 処理の種類(処理パターン)ごとに、計測期間の全サンプルの経過時間からパーセンタイル値を求める。レスポンスタイム(秒毎)の値を再集計してはいけません(秒ごとのパーセンタイルを平均・再集計しても、全体のパーセンタイルにはなりません)。 🔍集計方法はEを参照 |
詳細画面 180ms 検索・一覧画面 1,650ms ダウンロード 4,800ms(目標を定めないため参考値) (いずれも通常時の95%tile) |
| エラー率 | 処理結果 | エラーとなった件数を総件数で割る | 0.12% |
| タイムアウト | 処理結果 | タイムアウトとなった件数を数える | 0件 |
| リソース使用率 | 性能メトリクス(6-6) | 計測期間の平均値と最大値を求める | アプリケーションのCPU使用率 平均52%、最大78% |
9-2.合否の判定
各機能(API)の集計結果を、当てはめた処理パターンの合格基準(2-4)と照らし、指標ごと(レスポンスタイム・スループット・エラー率)に、通常時とピーク時それぞれについて判定します。
| 指標 | 対象 | 合格基準 | 集計結果 | 判定 |
|---|---|---|---|---|
| レスポンスタイム | 詳細画面 | 200ms以下(通常時の95%tile) | 180ms | 合格 |
| 検索・一覧画面 | 1500ms以下(通常時の95%tile) | 1,650ms | 不合格 | |
| ダウンロード | 上限を定めない | 4,800ms | ―(参考値。実測値をもとに改善方針を協議する) | |
| スループット | 打刻処理 | 12TPS以上(ピーク時、計測区間の平均) | 12.6TPS | 合格 |
| エラー率 | 全体 | 0.5%未満 | 0.12% | 合格 |
| タイムアウト | 全体 | 0件 | 0件 | 合格 |
| リソース使用率 | アプリケーションのCPU使用率 | 平均70%以下 | 平均52% | 合格 |
基準を満たせない場合(上の例では検索・一覧画面のレスポンスタイム)は、9-3を参考にボトルネックを特定して改善し、再テスト(9-4)を行います。
判定の途中で合格基準の不備に気づいた場合は、2-4に沿って見直し、再判定します。
9-3.計測結果の分析
合否にかかわらず、グラフで性能の安定性やエラーの有無を確認し、問題が見つかった場合は各証跡を突き合わせて原因を特定します。
a) グラフによる分析
スループット・レスポンスタイムをグラフにプロットし、下記観点などを参考にスループット・レスポンスタイムの安定性や目標性能(上限値)における挙動などを確認しましょう。
- 所定の仮想ユーザ数ごとのスループット・レスポンスタイム時系列推移
- レスポンスタイム(秒毎集計)をスループット(秒毎集計)を縦軸に、横軸に時間をプロットすることでスループットとレスポンスタイムの推移を視覚化することができます。
- 所定の仮想ユーザ数においてスループット・レスポンスタイムが安定していることを確認します。
- 仮想ユーザ数増に対するスループット・レスポンスタイム性能特性
- レスポンスタイム(計測期間全体)とスループット(計測期間全体)を縦軸に、横軸に仮想ユーザ数(または入力スループット)をプロットすることで性能特性を視覚化します。
- 仮想ユーザ数を徐々に増やしていったときの、スループット・レスポンスタイムそれぞれが描くグラフの傾きを確認します。
- 想定する最大の仮想ユーザ数においてスループットが大きく低下しないこと、レスポンスタイムが大きく悪化しないことを確認します。
性能目標を超えた負荷を与えるテストシナリオ(キャパシティテスト・ストレステストなど)では、システムの挙動やそこに至るまでの性能特性を明らかにします。性能限界が性能目標を下回っている場合はc)を参考にボトルネックの特定と改善を実施しましょう。一通りボトルネックが解消した後は下記事項に着目してシステムの性能特性を明らかにします。
- スループットが頭打ちになってから横ばいもしくは微増で安定していること(安定性)
- 仮想ユーザ数(または入力スループット)それぞれにおける実績スループット・レスポンスタイムが描くカーブを明らかにする(性能特性)
- スループットが低下し始めるポイント、レスポンスタイムが著しく悪化するポイントを見極める(性能限界)
スケールアウト・スケールインの挙動を確かめる場合(スケーラビリティテストなど)は、計測区間の外にあたるランプアップ・ランプダウンも確認の対象になります。台数が設定どおりに増減したか、エラーが発生していないかを確認しましょう。
b) 各証跡を突き合わせ問題を切り分ける
負荷ツールの記録を見て「あれ?」と思うところ(レスポンスタイムの目標未達、エラー、仮想ユーザ数の不足など)が見つかったら、同じ時刻の性能メトリクス(6-6)・ログのうち、照合すべきものを参照して怪しいところをあぶり出します。その結果として、被疑箇所が浮かび上がってきます。まず計測側にボトルネックがないかを確かめ、そのうえで製品側の切り分けに移りましょう。代表的な例を次の表に示します。
| 負荷ツールの記録 | 照合すべき性能メトリクス・ログ | 切り分け観点 | 被疑箇所 |
|---|---|---|---|
| 実行中の仮想ユーザ数が目標に届かない。待機時間(IdleTime)が意図より伸びている | 負荷ツールのマシンのCPU・メモリ使用率 | 使用率が高く、サーバ側には余裕がある | 負荷ツール(6-1) |
| 接続時間(Connect)が0でない要求が頻発している | サーバ処理時間 | keep-alive のタイムアウトより短い間隔の要求でも接続し直している。サーバ処理時間は短いのに、レスポンスタイムが長い | ネットワーク・接続(TCPの再接続、TLSハンドシェイクの繰り返し) |
| 特定の処理のレスポンスタイムが目標未達(例:検索・一覧画面) | サーバ処理時間、DBのCPU使用率、スロークエリ | サーバ処理時間も長い。DBのCPU使用率が高く、スロークエリが出ている | インデックスの不足による全表スキャンなど |
| 負荷の立ち上がり直後や急増時に、レスポンスタイムが伸びる | インスタンス数の推移、CPU使用率 | 最小台数のままCPU使用率が高い。またはインスタンス数が増えている途中 | 最小台数の設定、スケールアウトの追従(6-2) |
| ランプダウン中などにエラー(5xx)が発生 | インスタンス数の推移 | エラーの時刻にインスタンス数が減っている | Graceful Shutdown の考慮不足(6-2) |
| 特定の更新処理でエラーが発生 | エラー・WARNログ | 楽観ロックによる更新エラーや、ロック待ちのタイムアウトが出ている | テストデータの不備(7-4) |
| エラー(429・503 など)が発生 | サーバに届いた件数、APIゲートウェイ・ロードバランサーのエラー数 | サーバに届いた件数が、負荷ツールの送信件数より少ない | 前段の流量制御(C) |
被疑箇所が製品側でなく計測側(負荷ツール・テストデータ・計測条件など)にある場合は、それらを見直して計測し直しましょう。計測側の問題でない場合、製品側の原因の特定に進みます。よくある原因はc)も参考にしてください。
時刻の前後関係(エラーの発生とインスタンス数の増加のどちらが先か、など)は、グラフだけでなく元データで確認しましょう。
c) ボトルネックの特定とよくある原因
計測結果が目標性能に満たない場合、H/W・OS等計測メトリクスの分析やプロファイリングツールを用いてボトルネックを特定します。判明したボトルネックを参考に、インフラ設定やアプリケーションコードなどの改善点を究明しましょう。下記事項は性能テストでよくパフォーマンス問題を引き起こす例です。
- 過剰なログファイル書き出し(ログレベルの設定ミスやINFOログの大量出力等)
- 設定ファイルの過剰読み込み(ほぼ変更されない設定ファイルをリクエスト毎読み込んでいる)
- 不必要なスレッド同期処理によってスループットが伸びない
- マシンスペックの不足(コア単体性能、CPU数、メモリ容量、ディスクI/O性能など)
- クラスタノード数の不足
- N+1クエリ(一覧の件数の分だけSQLを繰り返し発行している)
- インデックスの不足による全件走査
- DBコネクションプールの枯渇(プールのサイズが必要な接続数より小さく、接続待ちが発生する)
- GC(ガベージコレクション)の多発や、GCによる長い停止
- Graceful Shutdown の考慮不足(スケールインの際に、処理中の要求がエラーになる)
9-4.再テスト
チューニングや不具合の修正を行ったら、同じテストシナリオを同じ条件で再度実施し、修正前の計測結果と比べます。条件が異なると、値の違いが修正の効果なのか条件の差なのか見分けられません(3-1)。
変更は、効果を切り分けられる単位・粒度で行いましょう(最小は一度に1つずつ)。切り分けられない形で複数の変更を同時に加えると、どの変更が効いたのか分からなくなります。また、修正によって別の処理が遅くなることもあるため、対象の処理だけでなく、テストシナリオ全体の結果を比べます。
再テストで基準を満たせない場合も、結果に合わせて合格基準を緩めることはしません(2-4)。
10.結果まとめ
計測・分析の結果を性能テスト結果レポートとして取りまとめます。総論はいわゆるエクゼクティブサマリとなります。検証概要から結果、課題などを簡潔にまとめましょう。各論には検証を行ったシステム構成、計測結果などを事実に沿って淡々と記述します。
総論の執筆にあたって大切なことは、想定読者が誰であるかを By Name で念頭におき、想定読者の視座に立ってレポートを執筆することです。自社サービスのCTO、顧客執行役員、顧客システム部長、顧客事業部門DX推進担当役員など、ポジションやロール、経歴によって関心や判断の基準は異なります。想定読者のIT知識・素養に応じてビジネスから語るのか、テクニカル面を全面に打ち出すのか、読み手が受け入れやすいストーリーでの執筆を心がけましょう。
(注:あえて検証結果を曲げる必要はありません。事実を曲げることは無用なトラブルの原因となり禁物です)
記述すべき項目は下記のようなものです。
- 総論
- 検証概要(背景・目的・検証内容・結果サマリ)
- 前提条件および検証観点
- テストシナリオ
- 検証結果
- 課題と対策案
- 各論
- 各テストシナリオと結果
- 所定の仮想ユーザ数ごとの検証結果
- 所定の仮想ユーザ数ごとのスループット・レスポンスタイム時系列推移
- 仮想ユーザ数増に対するスループット・レスポンスタイム性能特性
- H/W・OS等計測メトリクスの時系列推移
- システム構成
- 運用コスト
- 各テストシナリオと結果
おわりに
10章にわたって解説してきましたが、いかがだったでしょうか。ITスキルの中には向き不向きによって習得が難しい類のものもありますが、性能テストは標準的なプロセス・プラクティスが理解できていればトレーニングや反復によって習得することが可能です。また、性能テストのプロセス・プラクティスは環境・言語を問わず応用が効く、いわゆる「ポータブル・スキル」です。これを機会に性能テストに親しみを持って頂けたら幸いです。
Appendix.
A. オンライン性能とは
“オンライン”にも色々ありますが、本稿では「オンライン同期処理」を扱います。オンライン同期処理とは「クライアントからサーバ上の処理を呼び出し、サーバ処理が終了するまでクライアントへの応答が待機する、サーバ処理終了後クライアントへ応答が返る方式」です。その他のオンライン処理として下記のようなものがあります。
- オンライン非同期処理(リモート処理が登録できた段階でクライアントへ応答が返却される方式のこと)
- オンバッチ処理(オンライン処理からバッチ処理を呼び出す方式のこと)
- センタカット処理(バッチ処理からオンライン処理を呼び出す方式のこと。サーバ側部分のみを切り取って見るとオンライン同期処理そのものであるが、系全体としては異なる意味を持つ)
本稿はオンライン同期処理を中心に説明しますが、実際のシステムにはオンライン非同期処理の受付も含まれることがあります。オンライン非同期処理では、要求を受け付けた時点で応答が返り、実際の処理はその後もサーバ側で続きます。この場合のレスポンスタイムは受付までの時間であり、処理が完了するまでの時間は含みません。受付のレスポンスタイムと、処理が完了するまでの時間(状態の確認や完了の通知で測る)は、目標を分けて設定しましょう。
B. ボトルネックとは
ボトルネックとは「瓶(ビン)のすぼまった部分」のことです。システムは多くの要素(CPU、メモリ、ディスク…)から構成されておりそれぞれパフォーマンスに影響を及ぼします。ここで重要なのは「システム全体の性能は最も性能の低い要素に揃う」ということです。瓶を例に取ると、瓶内部を流体が通り抜ける際、最大流量(最大性能)は瓶の最もすぼまった部分の流量に等しくなることから律速あるいはボトルネックと呼ばれています。
OS(カーネルパラメータ)にも同時処理能力の限界が潜んでおり、TCPソケットの再利用待機時間、ファイルディスクリプタ同時利用数などのOSパラメータは意外に閾値が低いためH/W性能としては余裕があるのに性能が伸びないことがあり、この場合チューニングが必要です。Apache のようなWebサーバ、Tomcat のような Webコンテナにはスレッドプールサイズのようなパラメータがあり、このパラメータによって同時処理可能数を制限しています。
上記以外に、アプリケーション側でボトルネックを作り込んでしまうこともあります。例えばマルチスレッドプログラミングではセマフォ・ミューテックス等で複数スレッドによる同時書き込みから共有リソースを保護します。しかしその代償として並走度が犠牲となったりデッドロックが発生することがあります。高い並列性が求められる処理では読み書きロックの分離、CAS(Compare and Swap)などのテクニックを用いて並列性を改善します。
C. 流量制御とは
計算資源(CPU、メモリ、ディスクI/O…)は有限であり、処理能力を大きく超えた負荷が掛かり続けるとシステム全体の応答が著しく劣化したり、OS自体がハングアップ・再起動してしまうといったことがあります。
過負荷抑止などを目的に、サーバに流入する要求の量を制限することを流量制御といいます。流量制御には大きく2種類あります。
- 処理中のリクエスト数(F)を制限する:スレッドプールのサイズや最大接続数で、並行して処理する件数の上限を決める
- 単位時間あたりの件数を制限する(レート制限):1秒あたり・1分あたりの要求数の上限を決め、超えた要求を拒否する(HTTP 429 など)
流量制御の仕組みは、ロードバランサーやAPIゲートウェイ、サイドカープロキシといったネットワークコンポーネントのほか、アプリケーションサーバやWebサーバにも(スレッドプールやプロセス数などの形で)備わっていることがあります。
H/Wスペックに余裕があればスレッドプールサイズを増せる可能性がありますし、H/Wスペックが低い、DBサーバの処理能力が低いなどの場合はスレッドプールサイズを絞り込む(減らす)ことによって、過負荷によるサーバダウンやバックエンドDBサーバへの過負荷を抑止することができます。
APサーバを例に取ると、流量制御で設定された処理中のリクエスト数の上限を超えた要求は待機キューの最後尾に追加され、スレッドプールのワーカースレッドに空きがでたら待機キューの先頭から順に処理がディスパッチされます。FIFOキューのサイズ・待機時間にも上限が設けられておりいずれかを超過した要求はクライアント側にエラーが返却されます。クライアント側にはエラーが返却されますが、流量制御によってサーバに対する過大な要求が流入することが阻止されるためサーバの安定性を保ち続けることができます。
スレッドプールは全ての処理系に存在する訳ではありません。例えば Node.js では、クライアントから受け付けた要求を単一スレッドのイベントループ上で処理します。イベントループでは、DB・ファイル・ネットワークへのアクセスなどI/O処理の応答を待つ間に別の要求の処理へ切り替えることで、複数の要求を並行して処理できます(ネットワークI/Oは OS の非同期I/Oの仕組みで、ファイルI/O・DNS名前解決・暗号処理などは別に用意された少数のスレッド(既定4本)で完了を待ちます)。要求ごとにスレッドを割り当てないため、1接続あたりのメモリ消費やスレッド切り替えのコストが小さく、DBや外部APIの応答を待つ時間が長い処理(I/O待ちが中心の処理)で多数の接続を扱うのに向いています。C10K問題(1台のサーバで1万を超える接続を同時に扱う問題)への答えの一つとされるのはこのためです。
一方で、Node.js には、接続数の上限(server.maxConnections)はあるものの、処理待ちの要求の数や頻度を制限する仕組みは標準では備わっていません。処理能力を超える要求が届いても受け付け続け、処理待ちの要求がメモリ上に積み上がって、全ての要求の応答が一様に遅くなります。また、JSONの大きな変換や重い計算のようにCPUを使い続ける処理が1件あると、その間イベントループが止まり、他の全ての要求が待たされます。1プロセスが使えるCPUは実質1コアのため、複数コアを使うにはプロセスやコンテナを複数起動します。
このため Node.js のシステムでは、流量制御をアプリケーションの外側、つまりロードバランサーやAPIゲートウェイで行うか、アプリケーションに受付数やリクエスト頻度を制限する処理を組み込み、上限を超えた要求にはエラー(HTTP 429・503など)を返します。性能テストでは、CPU使用率に加えてイベントループの遅延(イベントループが処理に戻るまでの待ち時間)を監視すると、イベントループを止めている処理の有無を判断できます。
D. レスポンスタイムの目安
一般ユーザの離反率について、Google の調査(2017年、モバイルページの読み込み時間)では、読み込み時間が1秒から3秒になると直帰率が32%、1秒から5秒になると90%上昇するとされています。ユーザの体感レスポンスにはレスポンスタイムだけでなくWebブラウザの描画時間も含まれます。ユーザの体感レスポンスが目標2秒であり描画時間が0.5秒であるとすると、レスポンスタイムは1.5秒を目標とする必要があります。
留意点として、単純な処理と複雑な処理ではサーバ負荷や処理時間が異なります。全機能3秒以内のように画一的にレスポンス目標を決めるのではなく、ユーザ目線を意識しながら処理の複雑さも踏まえて決定しましょう。
E. 性能メトリクスの集計方法について
計測結果の読み取り方は重要です。テストシナリオは一定時間送信し続け、計測された値(複数)を所定の方法で集計します。レスポンスタイムとスループットでは値の性質が異なるため、集計方法を使い分けます。レスポンスタイムは要求1件ごとの値であり、分布をパーセンタイル値で見ることが多いので覚えておきましょう。スループットはある期間に処理した件数をならした値(2-3 b))であり、分布ではなく計測区間の平均で見ます。
| 指標 | 集計方法 | 説明 | 参考 |
|---|---|---|---|
| レスポンスタイム | %ile値 パーセンタイル値 |
計測値を昇順に並べたとき、指定した割合(例:90%)の位置にある値をレスポンスタイムとします。 計算方法(順位の端数の補間の有無など)はツールによって異なるため、JMeter・Azure Load Testing・Excel の値が完全には一致しないことがあります。 完全排除が難しい少数の外れ値・極端な値を除外した「大半の計測データ」に基づいて許容可能なレスポンスタイムを決定する場合に用います。性能テストでは%ileを用いることが多いです。 例)計測データの95%はレスポンスタイム○○秒以内を満たす(残り5%は○○秒を満たさないが許容する) |
EXCEL PERCENTILE.INC関数などを使用する。 |
| 中央値 | データを昇順で並び替え中心の値をレスポンスタイムとします。 実感により近い値が得られます。 ごく一部の極端に大きな値があっても中央値はほとんど動かないため、平均値と違って外れ値に強い(外れ値の影響を受けにくい)指標です。 例)レスポンスタイム速報値(中央値)は○○秒(外れ値の影響は受けにくい) |
EXCEL MEDIAN関数などを使用する。 | |
| 平均値 | 集計値の総和をデータの数で割った値をレスポンスタイムとします。 極端に大きな外れ値に引きずられることがあります。 例)レスポンスタイム速報値(平均値)は○○秒(ただし外れ値に引きずられている可能性あり) |
EXCEL AVERAGE関数などを使用する。 | |
| 最大値 | 計測されたレスポンスタイムのうち最も大きなものです。 1つの外れ値も許されないといったシーンで使用します。 例)全ての計測データはレスポンスタイム○○秒以内を満たす |
EXCEL MAX関数などを使用する。 | |
| スループット | 計測区間の平均 | 計測区間の総件数を計測区間の秒数で割った値をスループットとします。 合否判定にはこの値を用います。 例)打刻処理のスループットは計測区間の平均で12TPS以上 |
総件数を EXCEL COUNT関数などで数え、秒数で割る。 |
| ピークスループット | 秒ごとのスループットのうち、最も高い値です。 一瞬の最大値のため、合否判定には用いず参考値として記録します。 |
秒ごとの件数に EXCEL MAX関数などを使用する。 | |
| 秒ごとの推移 | 秒ごとのスループットを時系列で並べたものです。 グラフにして、計測区間を通して大きな落ち込みがないか(安定しているか)を確認します。 秒ごとの値を並べて「95%の秒で目標を満たす」のように判定することもできますが、一般的ではありません。 |
🔍9-3 a).グラフによる分析の時系列推移を参照 |
F. ユーザ数・処理中のリクエスト数・スループットの関係
システムに掛かる負荷は、ログイン中のユーザ数・処理中のリクエスト数・スループットといった数であらわされます。それぞれ何を数えたものかと、その関係を整理します。
| 指標 | 何を数えるか | 単位 |
|---|---|---|
| ログイン中のユーザ数 | ある時点でログインしてシステムを使っている人数。画面を読む・入力するといった操作の合間の人も含む。ログインしたまま操作していない人が多い場合は、アクティブユーザの割合(2-3 a))を踏まえる。ログインのないシステムでは、同時にシステムを使っている人数と読み替える | 人 |
| 処理中のリクエスト数 | ある時点で、サーバが受け付けてまだ応答を返し終えていない要求の数 | 件 |
| スループット | ある期間に処理を完了した件数を、単位時間あたりにならした値(2-3 b)) | 件/秒(TPS) |
処理中のリクエスト数とスループットは、どちらもサーバ側から見た数ですが別の指標です。処理中のリクエスト数はある時点の件数、スループットはある期間に完了した件数です。両者の間には「処理中のリクエスト数 = スループット × 応答時間」の関係があります(リトルの法則)。処理中のリクエスト数が同じでも、応答時間が短ければスループットは高く、長ければ低くなるため、どちらか一方だけでは性能を言いあらわせません。
ログイン中のユーザ数は処理中のリクエスト数とは一致しません。ユーザは操作の合間の時間(思考時間)には要求を送らないためです。思考時間を含めると、同じ関係は「ログイン中のユーザ数 = スループット ×(応答時間 + 思考時間)」となります。
(例)目標スループット10TPS、応答時間1秒、思考時間29秒の場合
- ログイン中のユーザ数 = 10TPS ×(1秒 + 29秒)= 300人
- 処理中のリクエスト数 = 10TPS × 1秒 = 10件
300人がログインしていても、サーバが処理している要求はある時点で10件程度です。
G. オープンモデルにおける到着頻度の求め方
オープンモデルでは仮想ユーザ数ではなく、単位時間あたりに利用を始める人数に基づき業務シナリオを開始する頻度(到着頻度)をテストシナリオにおける負荷として設定します。業務シナリオの中の待機(思考時間)は、そのまま含めて構いません。
| 性能要求の示し方 | 到着頻度の求め方 | 例 |
|---|---|---|
| 単位時間あたりに利用を始める人数 | そのまま用いる | ピーク時 8人/秒 |
| 目標スループット | 目標スループット ÷ 1周あたりの要求数 | 目標10TPS、1周あたり要求20件の場合、10TPS ÷ 20件 = 0.5回/秒 |
オープンモデルでは、応答が遅くなるほど同時に動く仮想ユーザが増えます。負荷ツール側で同時に動かせる数の上限は、「到着頻度 × 1周の所要時間」を目安に余裕を持たせましょう(例:8人/秒 × 45秒 = 360)。JMeter では、オープンモデルを Open Model Thread Group(JMeter 5.5以降)や、プラグインの Arrivals Thread Group で実装できます。
H. 負荷ツールの計測値と本稿の用語
負荷ツールで直接測れるのは、TTFB とレスポンスタイムです。サーバ処理時間は、サーバ側のログや監視のメトリクスで確認します。ネットワークレイテンシは直接は測りにくく、負荷ツールの接続時間(TCP の接続の確立は往復1回分)や、TTFB とサーバ処理時間の差から見積もります。
負荷ツールが表示する項目名は、本稿の用語と一致しないことがあります。JMeter の場合は次のとおりです。
| JMeter の項目 | 意味 | 本稿の用語 |
|---|---|---|
| Elapsed(経過時間) | 要求の送信開始から応答の受信完了まで | レスポンスタイム |
| Latency | 要求の送信開始から応答の最初の1バイトを受け取るまで | TTFB(ネットワークレイテンシではない) |
| Connect time | サーバとの接続(TCP・TLS)を確立するまで。Latency と Elapsed に含まれる | ― |
Azure Load Testing が表示する Response time は JMeter の Elapsed、つまり本稿のレスポンスタイムです。
以上