JMeterを利用した負荷テストでどのようにスレッド数、Ramp-Up期間、ループ回数をどうやって決めるか考える
what
前回の測定は、Ramp-Up期間がすべて 1 という極端なものであり、あまりよろしくないと聞いた。
そのため、再度、負荷テストを行う。
今回行いたい測定は、前回同様「サーバの負荷限界値」である。
負荷計測環境
前回とほぼ同じだが、負荷テスト対象のWebアプリケーションのバージョンが少々あがっている。
妥当なRamp-Up期間の決定について
JMeterで負荷テストするのはいいのだが、以下の数値をどのように決めるのに非常に悩む。
- スレッド数
- Ramp-Up期間
- ループ回数
どうしたらよいものか、考えてみた。
上記にテストシナリオ作成のヒントが書いてあるので読んでみた。「現実に即したテスト」という視点が非常に重要であると書いてある。
記事のヒット率の以下のようになる。
- スレッド数が大きい場合は、Ramp-Up期間を「0」に設定すべきではない。(異常な状態が好ましくない 。現実に即したものだとは言えない。 ヒット率の初期値が異常に高くなってしまう。)
- 「ヒット率の初期値を、できるだけヒット率の平均値に近い値に保つこと」が重要である。
- Ramp-Up期間が大きすぎるのも問題である。(ピーク時の負荷が過小評価されてしまう可能性がある)
実は、これからテストを行おうとしているアプリケーションは本番で数年走っているものであり、「ヒット率の平均値」はログを見れば分かる。
それは、「10ヒット/秒」である。
しかし、今回の負荷テストは「限界値」を求めるため、スタート値を平均ヒット率の2倍の 「 20 」まで上げて、テストしてみようと思う。2倍と軽々しく上げる理由は前回のスループットが160と出ているためである。
スレッド数が100で、ヒット率が20ヒット/秒と推定した場合、理想的なRamp-Up期間の推定値は、100÷20=5秒となる。
これで、以下のテストしてみようと思う。
負荷テスト
リクエスト
名称 | 対象サーバ | ポート番号 | プロトコル | メソッド | パス | その他(自動リダイレクト、リダイレクトに対応、!KeepAliveを有効にする、など) |
リクエストA | 192.168.0.5 | 80 | http | GET | /a/bbb | すべてOFF |
リクエストB | 192.168.0.5 | 80 | http | GET | /a/ccc | すべてOFF |
今回は、2つのリクエストパターンを同時に走らせる。
スレッドプロパティ
回数 | スレッド数(リクエスト数×スレッド数=スレッド数合計) | Ramp-Up期間(秒)(スレッド数合計/ヒット率の平均値) | ループ回数 | |
1回目 | 600(2×600=1200) | 60(1200÷20=60) | 1 | |
2回目 | 1200(2×1200=2400) | 60(2400÷40=60) | 1 | |
3回目 | 1800(2×1800=3600) | 60(3600÷60=60) | 1 | |
4回目 | 2400(2×2400=4800) | 60(4800÷80=60) | 1 | |
5回目 | 3000(2×3000=6000) | 60(6000÷100=60) | 1 | |
6回目 | 3300(2×3300=6600) | 60(6600÷110=60) | 1 | |
7回目 | 3600(2×3600=7200) | 60(7200÷120=60) | 1 | |
8回目 | 3900(2×3900=7800) | 60(7800÷130=60) | 1 |
上記のテストだと、ヒット率が期待するスループットになります。
実際には、以下のことも考慮してテストシナリオを作成することも重要であると書いてあるが、とりあえず無視してやってみる。
- ユーザーの思考時間の考慮
- レスポンス時間の要件定義
負荷計測結果
- 1回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 600 | 19 | 17 | 26 | 9 | 87 | 0.0 | 10.007839474254833 | 1.3780325838573548 |
リクエストB | 600 | 18 | 16 | 24 | 9 | 88 | 0.0 | 10.007338715057708 | 0.9870519631062779 |
合計 | 1200 | 19 | 16 | 25 | 9 | 88 | 0.0 | 20.008336807002916 | 2.364266360983743 |
- 2回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 1200 | 20 | 18 | 26 | 9 | 110 | 0.0 | 20.010672358591247 | 2.755375783751334 |
リクエストB | 1200 | 19 | 16 | 25 | 9 | 109 | 0.0 | 20.010672358591247 | 1.9737088947438632 |
合計 | 2400 | 19 | 17 | 25 | 9 | 110 | 0.0 | 40.0073346780243 | 4.727429195352482 |
- 3回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 1800 | 22 | 20 | 32 | 9 | 243 | 0.0 | 30.009503009286274 | 4.132167894833364 |
リクエストB | 1799 | 20 | 16 | 31 | 9 | 113 | 0.0 | 30.021360389827116 | 2.961091210324745 |
合計 | 3599 | 21 | 18 | 31 | 9 | 243 | 0.0 | 60.00233407245627 | 7.090445177431186 |
- 4回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 2400 | 31 | 23 | 54 | 9 | 308 | 0.0 | 39.99600039996 | 5.507261773822617 |
リクエストB | 2398 | 29 | 23 | 49 | 10 | 290 | 0.0 | 39.98932728546176 | 3.944259820148084 |
合計 | 4798 | 30 | 23 | 52 | 9 | 308 | 0.0 | 79.95867079958671 | 9.448892350348299 |
- 5回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 3000 | 67 | 54 | 127 | 12 | 397 | 0.0 | 49.98417167896833 | 6.882586139389193 |
リクエストB | 2998 | 65 | 54 | 123 | 11 | 316 | 0.0 | 49.96833227774259 | 4.928517148488283 |
合計 | 5998 | 66 | 54 | 125 | 11 | 397 | 0.0 | 99.9150438939881 | 11.807018196848295 |
- 6回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 3300 | 1428 | 1376 | 2586 | 18 | 3267 | 0.0 | 52.55446553701108 | 7.236503555389222 |
リクエストB | 3149 | 1422 | 1374 | 2558 | 12 | 3343 | 0.0 | 50.21928075911012 | 4.9532689029981665 |
合計 | 6449 | 1425 | 1375 | 2574 | 12 | 3343 | 0.0 | 102.70416613581348 | 12.182909571482035 |
- 7回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 3600 | 3685 | 3792 | 5433 | 13 | 20998 | 0.0022222222222222222 | 52.6200394650296 | 7.382107359497185 |
リクエストB | 3206 | 3689 | 3799 | 5439 | 38 | 21014 | 0.0028072364316905803 | 46.88162608759231 | 4.782921373473715 |
合計 | 6806 | 3687 | 3793 | 5435 | 13 | 21014 | 0.0024977960622979724 | 99.4811079441643 | 12.162931420375648 |
- 8回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 3900 | 5324 | 5094 | 12047 | 21 | 25767 | 0.03 | 54.26011464188325 | 9.37258699009405 |
リクエストB | 3332 | 5373 | 5094 | 13338 | 23 | 25651 | 0.028811524609843937 | 46.40539260744826 | 6.190907373750035 |
合計 | 7232 | 5347 | 5094 | 12759 | 21 | 25767 | 0.029452433628318585 | 100.61773053592297 | 15.55712050962769 |
Ramp-Up 0 でテスト
前回、Ramp-Up 1 で行ったが、それはよろしくないということで今回は Ramp-Upを 60 に設定して行ったのだが、ためしに Ramp-Up 0 で行ったらどうなるのか試してみた。
リクエスト
同じ
スレッドプロパティ
回数 | スレッド数(リクエスト数×スレッド数=スレッド数合計) | Ramp-Up期間(秒) | ループ回数 | |
1回目 | 1(2×1=2) | 0 | 1 | |
2回目 | 200(2×200=400) | 0 | 1 | |
3回目 | 400(2×400=800) | 0 | 1 | |
4回目 | 600(2×600=1200) | 0 | 1 | |
5回目 | 1000(2×1000=2000) | 0 | 1 | |
6回目 | 1500(2×1500=3000) | 0 | 1 | |
7回目 | 2000(2×2000=4000) | 0 | 1 |
Ramp-Up 0 の負荷テスト結果
- 1回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 1 | 42 | 42 | 42 | 42 | 42 | 0.0 | 23.809523809523807 | 3.278459821428571 |
リクエストB | 1 | 14 | 14 | 14 | 14 | 14 | 0.0 | 71.42857142857143 | 7.045200892857142 |
合計 | 2 | 28 | 42 | 42 | 14 | 42 | 0.0 | 34.48275862068965 | 4.074622844827586 |
- 2回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 200 | 1051 | 1042 | 1744 | 51 | 2094 | 0.0 | 83.89261744966443 | 11.551620176174497 |
リクエストB | 200 | 1802 | 1824 | 2049 | 435 | 2320 | 0.0 | 50.58168942842691 | 4.9890142893272635 |
合計 | 400 | 1426 | 1642 | 1970 | 51 | 2320 | 0.0 | 99.82530571499876 | 11.79576366358872 |
- 3回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 400 | 2053 | 2014 | 3595 | 56 | 4274 | 0.0 | 83.55964069354502 | 11.505770837685398 |
リクエストB | 400 | 3535 | 3696 | 4009 | 557 | 4282 | 0.0 | 51.092093498531106 | 5.039356878273088 |
合計 | 800 | 2794 | 3325 | 3925 | 56 | 4282 | 0.0 | 101.44559979710881 | 11.987224194775552 |
- 4回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 600 | 3113 | 2922 | 5205 | 60 | 10961 | 0.0 | 51.484468851896345 | 7.089170027458383 |
リクエストB | 600 | 5001 | 5099 | 5489 | 23 | 10917 | 0.0 | 51.65733964700818 | 5.095108695652174 |
合計 | 1200 | 4057 | 4771 | 5445 | 23 | 10961 | 0.0 | 102.75732145915396 | 12.14222255523206 |
- 5回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 1000 | 7210 | 4856 | 14088 | 112 | 21821 | 0.0 | 43.757931125016405 | 6.025262000612611 |
リクエストB | 1000 | 4548 | 4831 | 5413 | 23 | 21500 | 0.0 | 43.94059231918446 | 4.333984203357061 |
合計 | 2000 | 5879 | 4836 | 13073 | 23 | 21821 | 0.0 | 87.38967054094206 | 10.326318491654288 |
- 6回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 1500 | 11069 | 8895 | 21344 | 115 | 21592 | 0.3006666666666667 | 65.80679126085812 | 32.170609590243046 |
リクエストB | 1500 | 5094 | 3819 | 12269 | 16 | 21560 | 0.037333333333333336 | 56.56961834364157 | 8.128788985895309 |
合計 | 3000 | 8082 | 5078 | 21154 | 16 | 21592 | 0.169 | 112.62952395254543 | 35.62245996959003 |
- 7回目
Label | # Samples | Average | Median | 90% Line | Min | Max | Error % | Throughput | KB/sec |
リクエストA | 2000 | 12438 | 13891 | 21320 | 71 | 25594 | 0.373 | 70.33832735457551 | 40.32831513329113 |
リクエストB | 2000 | 6536 | 5025 | 14052 | 296 | 25257 | 0.066 | 65.87398307038634 | 11.745125325252792 |
合計 | 4000 | 9487 | 5755 | 21234 | 71 | 25594 | 0.2195 | 131.43195110731418 | 49.39505364066505 |
2〜4回目はスループットが 100 近くを示しており、今回の結果に近い値が出ている。しかし、エラーが出始める6回目以降は、正しいレスポンスが帰ってこないため、スループットが高めになっています。では、エラーが 0% のところのスループットを参考にすればよいのかといえばそうでもなく、5回目はエラーが 0% にもかかわらずスループットは 87 と出ています。よって Ramp-Up 0 による計測は、Ramp-Upが 60 のときより、計測しにくいという結果になりました。とはいえ、100に近い数字が出ていますので、参考にならないわけではありませんね・・・。
まとめ
Ramp-Up 0 というのは計測しにくいという結果になった。ただ、瞬間的な負荷(ピーク時の負荷)が過小評価されるのもよろしくないので、完全に無視できるものでもない。
負荷テストのパターンは山のようにあるため、正解というのはないと思うが、実際そのサーバが現実にどのような負荷を想定するかが重要であると思った。その結果が利用者にとって一番意味のあるデータだからだ。
サーバの負荷のタイミング、流れについて整理すると以下のようになる。
サービスが動いているサービスのスループット取得
1. 現在のログを分析して、リクエスト状況の調査
2. その調査に基づき、負荷テストシナリオを作成する
3. (多くは本番環境ではできないとおもうのでデモ環境で)負荷テスト実行
4. 現在、どのくらいのスループットなのかが取得できる。
サービスリリース前のスループット取得
1. リクエスト状況の想定
2. その想定に基づき、負荷テストシナリオを作成する
3. 本番のサーバ環境で負荷テスト実行。
4. 現在、どのくらいのスループットなのかが取得できる。
スループット取得後
1. サーバ負荷(リクエスト/秒、ロードアベレージ、CPU、メモリ、I/Oなど)を監視する。
2. (sarなどを見て)負荷が高くなってきたら、サーバを改善してより多くの負荷に耐えられるようにする。(メモリ増強、I/O負荷軽減、スケールアウト、アプリケーションの改造など)。
3. 現在のログを分析して、リクエスト状況の把握。
4. 新しくなったサーバ性能、アプリケーション性能の環境(多くは本番環境ではできないとおもうのでデモ環境)で、負荷テスト実施。
5. 現在、どのくらいのスループットなのかが取得できる。
負荷テストについて、まだまだ分からないことだらけなので、突っ込みお願いします><