はじめに
前回はJMeterにThroughputShapingTimer(プラグイン)を組み込んで、
グラフィカルに負荷量を調整する方法を説明しました。
JMeterでグラフィカルに変幻自在なアクセス負荷を設定する(前編)
↑アクセス負荷量の制御イメージ 公式ページより
簡単な使用法の紹介までで話が長くなってしまったので、今回は実践的な使い方を説明します。
前回のあらすじ
上司さんからWebサイトの性能試験を任されたA君。
「Twitterでバズった時のアクセス急上昇を試験したい」という上司からの無茶振りに対し、
ThroughputShapingTimerを使うことでA君はJMeterで期待に添う試験ができるようになりました。
しかしA君はまだ単一ページへの試験しか検証できていません。
Webサイトのアクセス実績に基づき、より複雑な試験シナリオの作成に奮闘するのであった。。。
Throughput Shaping Timer を使ってみる(応用編)
小ネタはこのくらいにしておき、早速試験パターンとJMeterの試験シナリオ作成を説明していきます。
この記事では以下3つの試験パターンをホップ・ステップ・ジャンプの流れでご紹介します。
- 1つの画面遷移パターンをシリアルに実行する
- 1つの画面遷移パターンをパラレルに実行する
- 複数の画面遷移パターンをパラレルに実行する
環境情報
- Mac(Catalina)
- Apache httpd server(2.4.x)
- Java8(Oracle java 8u202)
- JMeter(5.3)
環境復旧
Apacheが停止している場合は前回と起動手順が異なるので、備忘かねて残します。
疎通確認
JMeterからリクエストを送信することでも確認できますが、ここではCURLコマンドで確認します。
$ curl http://localhost:8080/index.html
curl: (7) Failed to connect to localhost port 8080: Connection refused
Failed
となった場合、前回使用したApacheに通信できていないことがわかります。
コンテナの状態確認
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e2dc7c3714ee httpd:2.4 "httpd-foreground" 6 days ago Exited (0) 5 days ago my-apache-app
Status
がExited
になっているので、コンテナが停止状態(正常)であることがわかります。
万が一Up
になっている場合はハング状態なので、一度コンテナを停止させます。
コンテナの停止(参考)
$ docker stop e2dc7c3714ee
コンテナIDを指定して停止します。
コマンド実行後に改めてコンテナ状態を確認し、Exited
になっていることを確認します。
(ダメだったらPC再起動ですね)
コンテナの起動
$ docker start e2dc7c3714ee
e2dc7c3714ee
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e2dc7c3714ee httpd:2.4 "httpd-foreground" 6 days ago Up 3 seconds 0.0.0.0:8080->80/tcp, 0.0.0.0:32772->8080/tcp my-apache-app
$ curl http://localhost:8080/index.html
hello
これで準備完了です。
1つの画面遷移パターンをシリアルに実行する
Amazonさんを例に挙げると、ほとんどの人が以下の流れでサイトを利用しますね
- トップページを表示する
- 商品を選択する
- 購入する
本パターンでは、ひとりのユーザが同じページ遷移を延々と繰り返す前提で負荷量調整をする方法を説明します。
状況設定
- ユーザはひとり
- ページ01 -> ページ02 -> ページ03 の順に画面遷移する
- 普段は15RPS(RequestPerSecond)だが、瞬間的に75RPSまで上昇する
アクセスの流れをJMeterで表現する
前回作成したスレッドグループを流用します
今回は試験用にコンテンツを用意していないので、同一のHTMLにクエリ文字を変えてアクセスすることで、3種類のURLへアクセスしていることにします。
ThroughputShapingTimerを設定する
負荷量を変更しています。
スレッドグループを設定する
スレッド数(並列度)を1に設定します。
JMeterを実行する
3つのURLに大体均等にアクセスできましたね。
(完全に均等でないですが、ThroughputShapingTimerちゃんはお茶目なので許してあげてください)
Apacheログ解析
$ docker logs e2dc7c3714ee | tail -1094 | awk '{print $4}' | sed 's_\[18/Oct/2020:__' | uniq -c
〜〜〜
16 13:20:00
14 13:20:01
16 13:20:02
14 13:20:03
16 13:20:04
14 13:20:05
15 13:20:06
26 13:20:07
38 13:20:08
50 13:20:09
63 13:20:10
75 13:20:11
63 13:20:12
51 13:20:13
39 13:20:14
27 13:20:15
16 13:20:16
14 13:20:17
15 13:20:18
14 13:20:19
〜〜〜
15RPSから75RPSまで上昇し、15RPSまで戻りましたね。
※これから何度か試験するので、今回のアクセス総数である1094行のログを確認対象にしています
※sedコマンドの区切り文字はスラッシュ以外も指定できるよ!とのアドバイスをいただき見やすくなりました
Apacheログ解析(シリアルであることを確認)
$ docker logs e2dc7c3714ee | tail -10 | awk '{print $4, $7}'
[18/Oct/2020:13:20:36 /index.html?test02
[18/Oct/2020:13:20:36 /index.html?test03
[18/Oct/2020:13:20:36 /index.html?test01
[18/Oct/2020:13:20:36 /index.html?test02
[18/Oct/2020:13:20:36 /index.html?test03
[18/Oct/2020:13:20:36 /index.html?test01
[18/Oct/2020:13:20:36 /index.html?test02
[18/Oct/2020:13:20:36 /index.html?test03
[18/Oct/2020:13:20:36 /index.html?test01
[18/Oct/2020:13:20:36 /index.html?test02
綺麗にページ01 -> ページ02 -> ページ03 の順でアクセスが来ていることがわかりますね。
1つの画面遷移パターンをパラレルに実行する
前回はひとりのユーザが同じページ遷移を延々と繰り返す前提で負荷量調整しましたが、実際のWebサイトではあり得ませんよね。
3人のユーザが同時に前回同様の画面遷移をする前提で負荷量調整をする方法を説明します。
状況設定
- ユーザは3人
- ページ01 -> ページ02 -> ページ03 の順に画面遷移する
- 普段は15RPS(RequestPerSecond)だが、瞬間的に75RPSまで上昇する
スレッドグループを設定する
スレッド数(並列度)を3に設定します。
※他の設定は前回同様です
JMeterを実行する
今回も3つのURLに大体均等にアクセスできましたね。
Apacheログ解析
$ docker logs e2dc7c3714ee | tail -1082 | awk '{print $4}' | sed 's_\[18/Oct/2020:__' | uniq -c
〜〜〜
14 14:44:50
15 14:44:51
14 14:44:52
15 14:44:53
15 14:44:54
14 14:44:55
16 14:44:56
14 14:44:57
16 14:44:58
13 14:44:59
28 14:45:00
38 14:45:01
50 14:45:02
65 14:45:03
75 14:45:04
63 14:45:05
51 14:45:06
37 14:45:07
28 14:45:08
15 14:45:09
15 14:45:10
15 14:45:11
15 14:45:12
15 14:45:13
〜〜〜
15RPSから75RPSまで上昇し、15RPSまで戻りましたね。
Apacheログ解析(パラレルであることを確認)
$ docker logs e2dc7c3714ee | tail -10 | awk '{print $4, $7}'
[18/Oct/2020:14:45:29 /index.html?test03
[18/Oct/2020:14:45:29 /index.html?test02
[18/Oct/2020:14:45:29 /index.html?test01
[18/Oct/2020:14:45:29 /index.html?test02
[18/Oct/2020:14:45:29 /index.html?test03
[18/Oct/2020:14:45:29 /index.html?test02
[18/Oct/2020:14:45:29 /index.html?test03
[18/Oct/2020:14:45:29 /index.html?test01
[18/Oct/2020:14:45:29 /index.html?test03
[18/Oct/2020:14:45:29 /index.html?test01
前回に比べてアクセス順が ページ01 -> ページ02 -> ページ03 の順ではなくなりましたね。
3人のユーザが同時にアクセスして順序が前後したことがわかります。
複数の画面遷移パターンをパラレルに実行する
前回までは以下のパターンを試験してみました。(パターン1)
- トップページを表示する
- 商品を選択する
- 購入する
今回は以下の画面遷移を別のスレッドグループとして追加します。(パターン2)
- トップページを表示する
- 商品を選択する
- 他のおすすめ商品を選択する
今回は
(パターン1)3人のユーザが同時に画面遷移をする
(パターン2)5人のユーザが同時に画面遷移をする
前提で負荷量調整をする方法を説明します。
状況設定
(パターン1)※前回同様
- ユーザは3人
- ページ01 -> ページ02 -> ページ03 の順に画面遷移する
- 普段は15RPS(RequestPerSecond)だが、瞬間的に75RPSまで上昇する
(パターン2)
- ユーザは5人
- ページ11 -> ページ12 -> ページ13 の順に画面遷移する
- 50RPS(RequestPerSecond)が継続的に発生する
アクセスの流れをJMeterで表現する
前回作成したスレッドグループを流用します。
以下の写真のように、スレッドグループを複製して配置します。
統計レポートはスレッドグループと同じ階層に配置してください。
複製した設定を以下のように設定変更します。
スレッドグループ:
スレッド数:5
HTTP リクエスト(test11):
パス:/index.html?test11
HTTP リクエスト(test12):
パス:/index.html?test12
HTTP リクエスト(test13):
パス:/index.html?test13
ThroughputShapingTimerを設定する
50RPSで均一にします。
※JMeterはいきなりフルパワーを発揮できないので、指定負荷量に到達するまで徐々に駆け上がるようにしましょう
JMeterを実行する
スレッドグループ1と2それぞれで均一の負荷量が保てましたね。
JMeterレポートを作成する
今回は試験内容が複雑なので、Apacheログの解析では期待通り動いているかの確認が困難です。
JMeterの標準機能でレポート出力し、結果を確認しましょう。
-
JMeterレポートのグラフ描写間隔を調整する
いきなり通常は実施しない手順ですが。。。
レポートはデフォルトでは1分単位でグラフを描写します。
今回は試験時間がとても短いので、グラフの描写間隔も短くします。
<JMeterを展開したディレクトリ>/apache-jmeter-5.3/bin/user.properties
を開きます。
76行目あたりにjmeter.reportgenerator.overall_granularity
というグラフの描写間隔の設定値があるので、コメントアウトを外して、60000ミリ秒から1000ミリ秒に変更します。 -
レポート生成に必要な情報を入力する
Result file (csv or jtl):統計レポートで指定した出力ファイル名
user.properties file:bin配下にあります(先ほど書き換えたファイル)
Output directory:どこでもOKです
JMeterレポートを確認する
-
生成されたレポートをブラウザで開く
先ほどOutput directoryに指定した場所にレポートが生成されているので、index.html
を開きます。 -
美しいグラフに感動する
ThroughputShapingTimer
で設定した通りの波形が見事に描けましたね!!
おめでとうございます、これであなたもJMeterマスターです!
後日談
A君「ついにJMterの設定が完了しました!」
上司「ありがとう、今回の性能試験はA君に一任するよ。頑張って!」
A君「はい!」
見事試験対象のWebアプリケーションを性能測定する準備ができたA君。
しかしここからが本当の地獄の始まりでした。
まだまだ経験が浅いA君は、これから立ちふさがるであろう数々の問題をまだ予想できていないのでした。。。
続編は予定しておりませんが、、、あえて次回タイトルをつけるのであれば
次回:「性能未達も、本番障害も、あるんだよ」
性能試験は問題発見の手段でしかありません。
A君の試験計画を上司さんがより妥当なものへと導き、A君が大小問わず様々な問題に対して関係者を巻き込んでいくことが、ハッピーエンドへの近道ですね。
A君はさておき、この記事でより豊かなJMeterライフを送れる方が一人でも増えたら嬉しいです。
Appendix
記事を書いていく中で「こういう点でつまずくかもしれない。。。」と思ったポイントをQA形式でまとめます。
他にも気になることがありましたらコメントください。
Q1 設定した負荷量に到達しない
A君「設定は正しいのですが、想定の負荷量に達しません。。。設定値を若干下回ります。。。」
上司「仕様?だよ」
今回の検証では少量の負荷しかかけていないので問題になりませんでしたが、数百RPSを超えたあたりから実測値が設定を若干下回ります。
OSSなのでそこは大目に見て、下回ることを前提に若干大目の負荷量を設定しましょう。
Q2 設定した負荷に全然到達しません。。。
A君「本番相当の負荷量を設定したのですが、実測値が大幅に下回ります。。。JMeterもエラーを吐いています。。。」
上司「エラーを見ないとなんとも言えないが、JMeterが限界に達しているかもしれないね」
JMeterはJavaで動くので、かなりリソースを消費します。
まずはJMeterに割り当てるメモリを増やしてみてください。
参考:
JMeterでOutOfMemoryが発生した場合の対応方法
メモリに余裕はあるが想定の負荷量に到達しない場合は、OSの接続上限数に達している可能性があります。
ファイルディスクリプタの上限数を引き上げてみましょう。
(よくわからない場合は基盤担当の人にやってもらいましょう!)
Q3 どう頑張っても期待の負荷量が出ません。。。
A君「いろいろ設定を見直したのですが、本番相当の負荷量が出ません。。。」
上司「JMeterサーバの限界かもしれないね。。。」
大規模システムは複数のサーバで処理を分散するように、1台のJMeterで出せる負荷量には限界があります。(一概には言えませんが。。。)
以下いずれかの方法でJMeterの処理を分散させましょう。
例:10台のJMeterに処理を分散する場合
- ThroughputShapingTimerの設定値を1/10にして10台のJMeterに配置して実行する
- 上記に加えてJMeterをMaster-Slave構成にする
参考:
AWSでJMeterのMaster/Slave環境を構築(CentOS 7)
FireWallとKeyStoreがミソですね
Master-Slave構成にすることで実行ログがMasterに集約されるので、レポート作成が楽になるのがメリットですね。
しかしサーバインスタンスが1台増えるので、コスト面がデメリットです。
さいごに
長くなってしまいましたが、今回の記事はこれで完結です。
記事を書くって結構大変だな、ということを実感しました。
今までQiita等々には何度も助けられていますが、なんとなく流し読みするばかりでした。
これからはもう少し噛み締めながら記事を拝見させていただこうと思います。
今回は性能試験に関する記事を掲載しましたが、本業はJavaフレームワークのカスタマイズをしています。
(SpringFrameworkとか)
Javaフレームワークは業務に関わる内容が多く記事にしにくいので、
これを機に今まで手をつけてこなかった分野に挑戦するのもありかなと思っています。
GitHubPagesとGitHubActionsでWebページでも作ってみようかなと思うのですが、
基盤->Javaフレームワークときて画面は一切触ったことないので、失踪しないよう頑張ります。