イントロ
お仕事でWEB APIの性能評価をする機会があり、それをやった際の備忘メモ。
遠い昔(ほんとに15年くらい前)にJMeterを使って性能評価をときどきやっていましたが、今ググってもまだ現役のようなので、今回もJMeterをつかいました。
てことであらためて再入門として、セットアップからHelloworld的なところまで整理しておこうと思います。
テスト対象サーバとか、環境の整理とか
環境の整理ですが、JMeterはコマンドプロンプトから使いますのでWindowsにJavaを入れておきましょう。
C:\Windows\System32>java --version
java 17.0.11 2024-04-16 LTS
Java(TM) SE Runtime Environment (build 17.0.11+7-LTS-207)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.11+7-LTS-207, mixed mode, sharing)
C:\Windows\System32>
またテスト対象のサーバですが、誰かのサイトに負荷をかけるわけにはもちろんいかないので、
の記事にでてくるBackendサーバ(RESTサーバ)をローカルにたてることにします。
サーバのセットアップ手順だけざっと記載すると(記事通りWSLでやってます。WSLにもJavaを入れておきましょう)
$ java --version
java 17.0.8 2023-07-18 LTS
Java(TM) SE Runtime Environment (build 17.0.8+9-LTS-211)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.8+9-LTS-211, mixed mode, sharing)
$
$ git clone -b init https://github.com/masatomix/spring-data-rest-example.git
$ cd spring-data-rest-example/
$ ./gradlew clean bootRun
これだけです。APIはたとえば
http://[サーバ名]:8080/companies?page=0&size=20
http://[サーバ名]:8080/users?page=0&size=20
とかが動くようになったと思います。
また、あとでプロキシを経由して接続する都合上、 localhostではなくIPアドレスでアクセスをしたいので、WSLの方で下記のようにIPを調べておきましょう。
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet 10.255.255.254/32 brd 10.255.255.254 scope global lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:15:5d:7a:26:0a brd ff:ff:ff:ff:ff:ff
inet 192.168.127.67/20 brd 192.168.127.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:fe7a:260a/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:5f:cd:00:30 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
$
192.168.127.67
をメモっておきます。
JMeterのインストールとセットアップ
https://jmeter.apache.org/download_jmeter.cgi よりダウンロード。2024/12/04時点の直近版は
のようですね。ダウンロードして、適当なところに展開しておきましょう。
さて起動します。
C:\Windows\System32>cd c:\javatools\apache-jmeter-5.6.3\bin\
c:\javatools\apache-jmeter-5.6.3\bin>jmeter.bat
================================================================================
Don't use GUI mode for load testing !, only for Test creation and Test debugging.
For load testing, use CLI Mode (was NON GUI):
jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
& increase Java Heap to meet your test requirements:
Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file
Check : https://jmeter.apache.org/usermanual/best-practices.html
================================================================================
起動したようですね!
まずは使いやすいように日本語に切り替えておきましょう。
Options > Choose Language > Japaneseを選択します。
とりあえずやってみる
ざっと必要な設定手順を書いていきます。これだけみてるとなんのこっちゃかもしれませんが、とりあえずやってみましょう。
負荷度合いやループ回数の設定
Test Plan > 追加 > Threads > スレッドグループ
スレッドグループの設定では、
- スレッド数
- 何秒かけてそのスレッド数に到達するか
- ループ回数(上の設定を何回ループするか)
などを設定します。たとえば
- スレッド数 5
- Ramp-Up期間 10秒
- ループ回数 1
とした場合、10秒で5スレッドを起動するので、2秒に1回(初回の)クエリが発行されることになります。徐々に負荷を高めていって、最終的なスレッド数に到達するイメージですね。
接続先情報を設定
つづいて接続先のサーバを指定します。
Test Plan > 追加 > 設定エレメント > HTTPリクエスト初期値設定
下記の設定が追加されました。
この画面は、リクエストの共通設定をする箇所です。よく使うのは「プロトコル」「サーバ名」「ポート番号」ですね。今回は
- プロトコル: http
- サーバ名: 192.168.127.67
- ポート番号: 8080
としておきました。
個々のリクエストを設定する
具体的なリクエスト(サンプラー)を追加します。冒頭で書いた
http://[サーバ名]:8080/companies?page=0&size=20
http://[サーバ名]:8080/users?page=0&size=20
を追加してみます。
スレッドグループ > 追加 > サンプラー > HTTPリクエスト
下記のような設定が追加されました。
なんとなくわかるかも知れませんが、HTTPのメソッドや/companies
などのリクエストパス、リクエストパラメータ(page=0
とかね)を設定する事ができます。共通部分のサーバ名などは「 HTTPリクエスト初期値設定」で設定済みなので省略可能です。
同様に /users
分も追加しておきましょう。
また名前について、判別できるように _companies
とか、_users
とかをつけておきました。
いったんCtrl-sで好きな場所に保存しておきましょう。
結果を表示するリスナーを設定
JMeterで負荷をかけたときに、リクエストが正しく実行できているかとか、平均レスポンスはどれくらいかな?とかを表示したいですよね。
それらを表示する「リスナー」を追加します。
Test Plan > 追加 > リスナー > 結果をツリーで表示
追加されました。
下記はテスト実行後の表示なのですが、リクエスト・レスポンスの結果など、リクエストごとの詳細結果を表示することができます。
つづいて統計レポート。
Test Plan > 追加 > リスナー > 統計レポート
追加されました。
このようにリクエストごとの(名前がキーで集計されてそう)
- 実行件数
- 平均、最大、最小、メジアンのレスポンスタイム
- 90/95/99パーセンタイルのレスポンスタイム
- スループット(件/s)
- エラー率
などを表示できます。
またCtrl-sで保存しておきましょう。
実行してみる
ようやく実行です。実行はボタン上部の再生マークで。
スレッドグループは
- スレッド数 5
- Ramp-Up期間 10秒
- ループ回数 1
の設定だったので、2つのAPIに2秒に一回リクエストが飛びます。合計10リクエスト。
サーバ側のログを見たり、さきほどのリスナー(ツリー表示や、統計レポートのこと)をみていると、リアルタイムに状況が分かると思います。実行結果は既出のキャプチャの通りです。
おつかれさまでした。
まとめ
実際に性能評価する場合は、
- 10分くらいずっと負荷をかける(スレッドグループの設定で、ループ回数を無限、持続時間で10分を指定)
- 一様乱数タイマーを使ってリクエスト間隔をばらけさせることで、リクエストが周期的に集中しないようにする
- APIごとの利用度合いによってリクエスト負荷を調整したいので、スレッドグループを複数作って負荷を調節する。
- GUIで実行するのではなく、CUI(コマンドライン)からJMeterを実行して、計測結果をファイル出力にしてグラフィカルに集計
- 実はエラーでコケてたりしないよう、リクエストごとの実行結果が正常かをアサーションする
- 手動でチマチマシナリオ(今回作ったヤツ)を作るのは大変なので、プロキシ機能でリクエストをキャプチャしてシナリオを作る
などなどのナレッジがあったりしますが、まずはHelloWorldレベルは完了です。お疲れさまでした。
TIPS
プロキシ機能でキャプチャ
さきほどリクエスト(サンプラー)を設定しましたが、一つ一つ手動で設定していくのはとても面倒なので、JMeterの電文キャプチャ機能を使ってみます。ながれとしては
- ブラウザでプロキシ設定する(JMeter経由のリクエストにする)
- ブラウザでWEB操作(今回はSwaggerがあるのでそれを使います)
- そのリクエスト情報がJMeterに記録される
こんな感じです。
JMeter側の設定
まずはJMeterに設定を追加していきます。
Test Plan > 追加 > Non-Testエレメント > HTTPプロキシサーバ
ポートが8888であることを確認しつつ、あとで戻ってくるのでいったん次にいきます。
スレッドグループ > 追加 > ロジックコントローラ > 記録コントローラ
リクエストを記録する用のコントローラが追加されました。1
再度プロキシサーバの設定に戻って、記録先を「記録コントローラ」にしておきます。
開始をクリックすると、
警告みたいなのがでますが、このままOKします。
プロキシ機能が起動したようです。
ブラウザ側の設定
ブラウザ側をJMeter経由でリクエストするための設定をします。といってもよくあるプロキシ設定です。
Chromeとかだと下記のインターネットのプロパティから。JMeterのプロキシをポート8888であげておくので
- アドレス: http://localhost
- ポート: 8888
としました。
設定した時点でOSのリクエストがJMeter経由になっちゃうので、実際は下記のリクエストを投げる直前にOFF/ONした方がいいです。
さてChromeを起動して、おなじみのSwagger画面( http://192.168.127.67:8080/swagger-ui/index.html )へ。
Executeボタン等で実行してみると、、、
おお、リクエストがキャプチャされましたね!
詳細もみてみると、さきほどは手動で設定したリクエストが自動でセットされていることが分かります。
リクエストヘッダもちゃんとキャプチャしてくれていますね。手動じゃめんどくてできない、、。
キャプチャが終わったら停止をクリックしてキャプチャ機能を停止しておきましょう。
ブラウザのプロキシ設定を戻すのも忘れずに。
おつかれさまでした。
GUIではなく、コマンドプロンプトから実行する
GUIで起動すると実は、
Don't use GUI mode for load testing !, only for Test creation and Test debugging.
For load testing, use CLI Mode (was NON GUI):
jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
& increase Java Heap to meet your test requirements:
Modify current env variable HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m" in the jmeter batch file
Check : https://jmeter.apache.org/usermanual/best-practices.html
って 「GUIでは負荷テストするなよ!テスト作成とデバッグの時だけね」って書いてあるので、指示通りCLI(GUIじゃなくてプロンプトとか) から実行しようと思います。
その際のパラメタも書いてあるので指示通りにやってみると、、。
C:\Users\xxx\Desktop\result> c:\javatools\apache-jmeter-5.6.3\bin\jmeter.bat -n -t "..\sample.jmx" -l result.jtl -e -o output
WARN StatusConsoleListener The use of package scanning to locate plugins is deprecated and will be removed in a future release
WARN StatusConsoleListener The use of package scanning to locate plugins is deprecated and will be removed in a future release
WARN StatusConsoleListener The use of package scanning to locate plugins is deprecated and will be removed in a future release
WARN StatusConsoleListener The use of package scanning to locate plugins is deprecated and will be removed in a future release
Creating summariser <summary>
Created the tree successfully using ..\sample.jmx
Starting standalone test @ 2024 Dec 12 14:36:49 JST (1733981809986)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary = 10 in 00:00:08 = 1.2/s Avg: 20 Min: 8 Max: 101 Err: 0 (0.00%)
Tidying up ... @ 2024 Dec 12 14:36:58 JST (1733981818226)
... end of run
C:\Users\xxx\Desktop\result>
10秒ほどするとテストが完了しました。上記にサマリが書いてありますが、10件実行されエラーは0件なので、どうやらOKそうですね。
また、指定した箇所に jtlファイル(実行結果の素データ) とHTMLファイルが出力されています。そのHTMLを開いてみると、、
例: 統計レポートぽいやつ
例: パーセンタイルごとのレスポンスタイム
などなど、実行結果の統計情報がHTMLでグラフィカルに出力されていました。
関連リンク
- https://jmeter.apache.org/ 公式
- https://www.masatom.in/pukiwiki/JMeter/ 15年以上まえに整理した記事。しかも途中で力尽きている
- https://christina04.hatenablog.com/entry/2017/10/03/190000
- https://ptune.jp/tech/scenario-creation-method-using-http-proxy-server/ めっちゃ丁寧にJMeterを解説しています。
-
単にクリアボタンがあるコントローラと思われる ↩