さて、いよいよ今回は、JMeter最終回。シナリオの実行編です。
今までは主にJMeterを使ってWebシステムの性能テストを実施するために必要なテストシナリオを作ってきました。
ここまで読んできて頂いた方の手元には、あなたがテストしたいWebシステムへリクエストを送信するためのJMeterのテストシナリオファイル(JMXファイル)が出来ていると思います。
今回は、この記録したシナリオの使い方を紹介します。JMeterでWebシステムに対して実際に負荷をかけていく性能テスト(ストレレステスト)のやり方について書きたいと思います。
負荷の調整
負荷のかけ具合は、性能テストの肝となる部分です。この負荷の調整を間違えると正しいテストが実施できないだけでなく、設備に想定外の負荷を与えてしまうことになります。
さて、負荷の調整方法はいろいろありますが、今回紹介するのは次の二種類です。
- スレッドプロパティ
- タイマー
負荷の調整① スレッドプロパティ
基礎プロパティ
スレッドプロパティでは、作成したテストシナリオをどれぐらいの密度で何回実行するかを決定します。主に次の3つの要素で行います。
項目名 | 説明 |
スレッド数 | システムにアクセスする同時ユーザ数 |
Ramp-Up期間 | 指定したスレッドがすべて立ち上がるまでの時間 |
ループ回数 | シナリオを繰り返す回数 |
設定する時のコツ

同時にアクセスするユーザが100人のシステムであれば、スレッド数を100にします。あとはどれぐらいの密度でアクセスされるかをRamp-Upで指定します。
一気にアクセスが集中しそうなシステムの場合は、Ramp-Upは小さくします。0にすると一気に100スレッド立ち上げようとします。逆にポツポツとアクセスがあるような場合は、Tamp-Upを大きくします。
例えば、1分間に100人のユーザが殺到する状況を作るなら、Ramp-Upは60。10分間に100人のユーザがポツポツと来るならRamp-Upは600となります。
そして、それを何回繰り返すかをループ回数で指定します。シナリオ内のHTTPサンプラがすべて実行されると1回とカウントします。ループする場合は、スレッドが1つ終了すると次のスレッドが起動します。
この3つのパラメータでかけたい負荷を計算して出すのが正攻法だと思います。
ただ、テストシナリオの長さによってはテスト中盤に多重度が上がり想定していた負荷がうまく掛けられないこともあります。
私は計算が嫌いなので、机上での計算はそこそこに大体の負荷の掛け具合が決まったら、実地で試してから調整するようにしています。
私がよくやるのは、低めの負荷から始めて少しずつ高めていき、どこまで耐えるかという感じで実施しています。SLAで指標が定められている場合でもそのやり方で指標を満たせるところまで試せばよいと思います。
ここでは私のやり方を紹介しましたが、きちんと論理立ててシナリオを作りたいという方はJMeterの書籍をこのページの最後で紹介していますので、そちらをご覧ください。
負荷の調整② タイマー
単純な負荷試験の場合は、タイマーは使わなくてもよいでしょう。
タイマーを使うケースとしては、長時間運用試験のような一定期間、人間が実際に利用している状況に似た状態を作り出す場合に利用します。
HTTPサンプラーはWebシステムに対してリクエストを送信し、レスポンスを受けるとすぐに次のサンプラーを実行します。
実際の人間の動作では、Web画面に設置されたボタンをクリックして、サーバーからレスポンスデータを受信したブラウザは次の画面を描写します。ユーザはその画面を見てから次のアクションを起こします。つまり次のリクエストを送信するまでにインターバルが生まれます。
テストシナリオを実行すると、ブラウザがレスポンスを受信して画面を描写する前に次のアクションを起こしているような状態ですので、ちょっと人間のアクセスと違います。
JMeterで人間が利用しているようにリクエストを発行するには、シナリオにタイマーを追加します。
定数タイマー
コントローラーに追加すると、次のHTTPサンプラーが実行されるまで一定時間停止することができます。これによりリクエストの密度を下げることができます。
一様乱数タイマー
定数タイマーと同じですが、こちらは一定時間ではなく、指定した範囲内で停止時間に乱数が使えますので、より人間に近いリクエストが実現できます。

必ず試し実行をする
試し実行とは、まだ負荷をかけず、テストシナリオが正しく動作するか、Webシステムからの応答は正常かどうか必ず確認してから本実行をしましょう。
試し実行のやり方
次のようにスレッドグループのプロパティで、スレッド数、Ramp-Up、ループ回数をすべて1にセットします。これにより、テストシナリオが一回だけ実行できます。
まずはこれを実行して想定どおりのレスポンスが返ってきているか確認します。

テストシナリオの実行と停止はこのアイコンをクリックすると実行、停止が行えます。
試し実行結果の確認ポイント
シナリオの実行結果を確認するには、リスナーを追加します。
結果をツリーで表示と結果を表で表示の二種類を追加します。前回からの続きの方は既に追加されていると思います。

HTTPサンプラーのステータスが正常か
各HTTPサンプラーのStatus欄を確認します。左のように緑のチェック印が表示されれば正常にサーバ側にリクエストを送信して、HTTPステータスコード200(正常)で戻ってきています。
右側のように赤のバツ印の場合は、サーバ側から500(異常)のステータスコードが戻ってきています。まずは、HTTPサンプラーの中身を確認します。
- プロトコルは正しいか
- サーバ名を指定している場合は、名前で正しい、かつ名前解決できているか
- ポート番号は正しいか(プロトコル指定している場合は空欄でOK)
- HTTPリクエストのメソッドとパス文字列は正しいか
- リクエストで送るパラメータに誤りはないか
- 内部でリダイレクトしている場合があるのでリダイレクトに対応にチェックを入れる
HTTPサンプラーに問題が見当たらない場合は、Webアプリケーションサーバ、及びそこまでのルート上に問題がないか確認します。
- サーバ側のログにアクセスが記録されていないならHTTPサンプラー設定にミスがあるか、クライアントとサーバ間のファイアウォール等でリクエストが遮断されている
- サーバ側のログでテスト対象のシステム本体のエラーの場合はそれを修正する
- データベースを使っている場合は、接続設定ミスやコネクション枯渇
- ストレージを使っている場合は、パーミッション設定ミスや容量枯渇
- システム連携先が負荷に耐えきれなくてエラー
レスポンス内容は正しいか
HTTPスターテスは正常で終了していても、意図した通りに動作しているかは別問題です。それについては、結果をツリーで表示の応答データのタブで確認します。
実際にWebサーバからの応答文字列がそのまま確認できますので、ここで想定どおりのレスポンスかどうか確認します。
HTTPスターテスは200で正常に返ってきているので安心し、本実行して散々負荷を掛けてテスト実施結果、想定した応答ではありませんでしたというパターンが多いのでここでの確認は重要です。

ログインに失敗しているのにそのままシナリオが流れてしまうパターン
特に未ログインの場合はログイン画面を表示するような仕様のシステムの場合はログイン後もシナリオが正常に流れますが、レスポンスの中身を確認するとすべてログイン画面を表示するレスポンスで、想定していた負荷がまったくかかっていなかったということがあります。
シナリオ記録時とURIが変わっているパターン
特にシナリオテストのリグレッションをする場合によくあります。システムの改修を行ったあとに再実施すると一見うまく動作しているようでレスポンスの中身が異なっており正確にテストできていなかったというパターンがありますので、本格実施の前に試し実行は必須です。

テストシナリオ実行前準備
性能統計データ取得用リスナーの追加
統計レポート
イメージ

性能テストでは、数千~数万と言った多数のリクエストを送信します。手で集計するのは面倒です。
JMeterでは、それらの応答時間の最大、最小、平均やスループット、平均データ転送速度、エラー発生率などを自動的に集計するリスナーが用意されています。これをシナリオに追加しておくだけで統計情報が自動で集計できますので便利です。
追加方法
追加する方法も簡単で、他のリスナー同様、コントローラーの中に追加するだけです。

レスポンスタイムグラフ
イメージ

HTTPサンプラー別に時間ごとのレスポンスタイムをグラフで表示してくれます。どのリクエストの処理が重いのか、また時間が経過するごとに性能が劣化するかどうかもグラフで確認できます。
追加方法
追加する方法も簡単で、他のリスナー同様、コントローラーの中に追加するだけです。

あとは、この後テストシナリオを実行した後に確認してみましょう。
サーバ側リソース利用状況の監視・記録
性能テストを実施する際には、サーバ側のリソースの状態を監視、記録しましょう。
どのぐらいの負荷をかけた時に、サーバ側のリソース(CPU使用率、メモリ使用率、ストレージI/O、ネットワーク転送量等)を使うのかを確認しておく必要があります。
例えば、AWSならCloudWatchを使えばアプリケーションサーバ(EC2)やデータベースサーバ(RDS)の状態が監視・記録できます。
また、自前サーバの場合でも、Linuxサーバなら、vmstatコマンドやfreeコマンドで、Windowsサーバーならタスクマネージャーでリソースの利用状況を確認できます。
そんなわけで、性能テスト実施前に、監視・記録体制は整えておいたほうがよいでしょう。仮に性能テストでエラーは発生しなかった場合でも、ギリギリ大丈夫だったのか、十分な余力を残していたかよって、対処の要否が別れます。ギリギリ大丈夫だった場合は、安定度を上げるため、リソースの増強の検討の余地がありです。
性能テスト(ストレステスト)の実行
テスト開始
テスト自体はJMeterがWebサーバに対してリクエストを送信してくれるので、手を出す必要はありません。
テスト実行時はどのリスナーを眺めていてもよいので、気になるところ、好きなところを眺めていましょう。私はテスト実行状況がリアルタイムで分かる「結果を表で表示」のところをよく見ています。

「結果を表で表示」と「結果をツリーで表示」は、画面下部にScroll automatically? という項目がありますので、これにチェックを入れると自動でスクロールしますので、リクエスト投げている感が出ます
テスト実行中にやること
高負荷時発生中のシステム利用感の確認
高負荷時にシステムはどんな動きをするのか気になる場合は、ブラウザを起動してシステムを使ってみるとよいと思います。応答時間の遅延などを感じようなら、リソース増強の検討の余地ありです。
サーバ側のリソース利用状況の監視
テスト実行中は、JMeterを実行中のマシンのリソースの状態もモニタリングしておきましょう。JMeter実行マシンの性能不足で指定した負荷がかけられなかったというケースもよくあります。

CPU使用率
タスクマネージャで確認すると、まだまだ余力があるので問題はありませんが、CPU使用率が100%に張り付くとリクエストの送信密度が下がりことが多いです。100%張り付いてしまった場合は、性能の良いマシンで実施しましょう。それが難しい場合は、JMeterのプロセスの実行優先度を上げれば少しはマシかも知れませんが、あまりオススメはしません。
JMeterのJavaVMメモリ使用率
JMeterはJavaVM上で動作しますので、タスクマネージャ上では確認できません。JStatなどでJMeterのJavaVMのメモリ使用率を確認します。
これが不足するとGCが発生し、GC処理にリソースを食われて、ほとんどリクエストを送信できなります。大きいテストシナリオを実行する場合は、JMeterのJavaVMメモリを多めに割り当てて起動しましょう。
性能テスト実施後の確認ポイント
統計レポートでエラーの確認
表示方法

確認ポイント
長時間リクエストを投げ続けると、短時間では発生しなかった問題が発生することがあります。むしろそれをシステム本番前に発見するための性能テストですので、ほどよく負荷をかけて見つけていきましょう。
シナリオを実行し終えたら、まずは統計レポートでError発生率を確認しましょう。基本的にはError発生率がすべて0%である必要があります。
次のようにHTTPリクエストサンプラー毎にエラーの発生率がわかります。ログイン処理周りでエラーが発生しています。
エラーが発生したからと言ってすぐにそれがダメだということではありません。エラーの内容を確認するのはもちろんですが、仕様上想定した以上の負荷がかかっている可能性もありますので、その場合は負荷の再調整をしたりします。

レスポンスタイムの確認
表示方法

確認ポイント
エラーが発生しないようになったら、次はいよいよレスポンスタイムを確認します。統計レポートでも確認できますが、グラフの方が直感的にわかりますので、レスポンスタイムグラフで確認します。
Webシステムには「3秒ルール」というものがあり、ユーザはこれ以上待たされると離脱してしまう、Webシステムの場合はストレスを感じてしまうという統計結果に基づく指標があります。
サーバからの応答が遅い場合は、それを改善します。Webシステムのレスポンスタイムは様々な要因によって性能遅延が発生しますので一概には言えませんが、次のようなステップで確認していくと何か原因が特定できるかも知れません。
短めに試し撃ち
縦軸がレスポンスタイムで、横軸が時間の経過です。折れ線グラフの色はHTTPサンプラの種類です。緑の線がログイン処理、他の色はログイン後の各機能の画面表示です。
今回の試したシナリオでは緑線がログイン処理、データベース検索と更新処理が行われるため重いです。水色やピンクの線はデータベース更新処理のみ、灰色と樺色の線はインデックスキーでの1件検索処理です。
100スレッドを2分で起動する設定で試したのでぐんぐん負荷が上がっています。ちなみに上り調子のまま終わっているため、この後更に上るのかどうかがわかりませんね。もっと実行時間を延ばして経過を観察する必要があります。

10分間実行してみる
さきほどはサンプル数が少ないので、10分程度実行してみます。するとやはりあの後ぐんぐんとレスポンスタイムが伸びてしまっています。
開始1:30で3秒ルールを超えてしまいました。その後も性能が劣化していき、開始から4分で重い処理は応答時間10秒を超えてしまいました。軽い処理でも6秒かかっています。
このような感じでレスポンスタイムの推移もわかりますので、どのぐらいで性能劣化がどれぐらい発生するかよくわかります。

サーバ側のリソースを確認してみましょう。本当はいろいろなリソースをモニタリングするのですが、今回はシンプルにCPUの使用率だけ見てみます。
左側がWebサーバ、右側がデータベースサーバのCPUの使用率です。Webサーバ側が100%近いところまで到達しています。ここで処理遅延が発生していたようです。

Webサーバのリソースを増強して再実行
オンプレ環境だとサーバ側のリソース増強が必要だなんてことになったら一大事件に発展しますが、クラウドサービスはさすがです。Webの管理画面でマウスをクリックするだけで簡単なサーバ側のリソースを追加できてしまうので便利です。
Webサーバを動かしているEC2のインスタンスを強化して再度実行してみます。
おお、全リクエスト1秒以内で応答していますね!!

まとめ
JMeterを使った性能テストの実施はうまく実施できたでしょうか?
Webシステムはどんなにおしゃれに作っても、どんなに機能が豊富でも、応答速度が遅いと利用者はこのサイトは重いな、、と良い印象を持ちません。そして離脱率も上がり利用率も下がってしまいます。
SLAの性能要件を満たせなかった場合は、成果物責任を問われてしまう問題にも発展するため、性能テストはとても重要です。
本番稼動する前の性能テストは大変重要なフェーズですので、開発計画を立案する際には必ず組み込みましょう。
一般的にはシステム開発の終盤のシステムテスト工程で実施されることが多いですが、新しいアーキテクチャを採用した場合などはプロトタイプを作成した時点で一度性能テストを実施しておいた方がよいでしょう。
システム開発終盤のシステムテストでアーキテクチャの選択ミスやシステム基盤設計の問題で性能が出なかった場合に取り返しがつきません。
これでJMeter企画は一旦終了です。JMeterは実にいろいろなテストが実施できますし、シナリオが組めるので負荷テスト以外でもテスト自動化なども可能です。
詳しく知りたい方はやはり書籍がオススメです。
- テスト実施前にシナリオが正しく動作するか確認する
- 負荷のかけ具合はざっくり計算して決めたらあとは実行して調整する方が早い
- 本格実行する前には試し実行をする
- 本格実行後はまずエラーの有無を確認
- すべて正常になったら次はレスポンスタイムの確認
- テスト結果の集計、応答時間のグラフ化などはJMeterの機能でできる
システム開発に性能テストは不可欠です。ほとんどのシステム開発現場で性能テストを実施しましたので、JMeterの使い方は習得しておいて損はありません。むしろ推奨します。
そして求められる性能が出せない場合は、チューニングしましょう。ここまでがワンセットです。
プログラミングは独学ではなかなか難しい時もあります。そんな時はプログラミングスクールで教わってしまうのも上達への近道です。

コメント