負荷試験やりました!JMeterで作ったシナリオをAWSのDLTで実行する
はじめに
現在開発中のwebサービスに対して、JMeterで作成したシナリオをAWSのDLT(Distributed Load Testing)を使って実行し、負荷試験を実施しましたので得た知見を共有します。
(※DLTは自分のAWSアカウント上に構築するものなので、正式なサービス名があるわけではないので、便宜的にAWS DLTと呼ぶことにしています。)
実現したかったこと
実現したかったこと | できたか | どちらの機能か |
---|---|---|
費用を抑えたい | できた | JMeterは無料、DLTは低コスト |
簡単にはじめたい | できた | JMeterは慣れが必要、DLTは簡単 |
高負荷をかけたい | できた | DLT |
自由にシナリオを決めたい | できた | JMeter |
シナリオ作成ツールを自由に選びたい | DLTはJMeterだけだった | DLT |
1秒間に何回リクエストをするかコントロールしたい | できた | JMeterとDLTの合わせ技 |
ログインだけ最初の一回でそれ以外をループしたい | できた | JMeter |
ランダムにリクエスト内容を変えたい | できた | JMeter |
数万あるページに満遍なくリクエストしたい | できた | JMeter |
複数のユーザーでログイン試行したい | できた | JMeter |
SPAサイトへ負荷をかけたい | 裏側のAPIにだけ負荷をかけた | JMeter |
結果レポートを簡単に見たい | できた | DLT |
JMeterとは
JMeterはApacheソフトウェア財団が開発・提供しているオープンソースの負荷試験ツールです。JMeterはJavaで開発されており、WebアプリケーションやWebサービス、データベース、FTPサーバーなどのさまざまなシステムやプロトコルのパフォーマンスをテストするために使用されます。
AWSのDLT(Distributed Load Testing)
DLTはAWSが提供する負荷テストのサービスです。名前が長いので勝手にDLTと略して呼んでいます。AWSのクラウドインフラストラクチャを利用して、複数の仮想ユーザーが同時にアプリケーションやシステムにアクセスする負荷をかけることができます。
構築は非常に簡単で、上記にアクセスしAWSアカウントを持っている人が以下のボタンをクリックすると、「管理者名」「メールアドレス」を入力する必要があるくらいで、デフォルトのまま進めていくだけで、ログインしているAWSアカウント上で構築が始まります。
構築が終わったら入力したメールアドレスにパスワードが送られてくるので、DLTにログインするだけですぐにでも負荷試験を開始できます。構成は以下の図のとおりで、負荷をかけているときだけタスクが起動し、終了すると全てのタスクが停止するようになっているため費用をあまり気にしなくてよいのが嬉しいです。
ログインして「CREATE TEST」をクリックすると以下のような画面が表示されます。
左側には以下のような設定項目があります。
項目名 | 説明 |
---|---|
Name | この負荷テストの名前 |
Description | この負荷テストシナリオの短い説明 |
Task Count | ECS Fargateのタスク数を指定できます。何台のサーバーで負荷をかけるかというイメージです。20台のサーバーで負荷をかけたい場合は20と入力します。(最大1000) |
Concurrency | 1タスクあたりの仮想ユーザーの数です。シナリオは1タスクの中でConcurrencyで指定した数だけ同時に実行されます。同時実行数や、同時接続数といったイメージです。 (最大200) |
Region | AWSのリージョンを選択します。 |
Ramp Up | Concurrencyで指定した仮想ユーザー数に達するまでの時間を指定します。仮に仮想ユーザー数を200にしたとしてもRamp Upが0だと、よーいドンで同時に200人が一斉にログインシナリオを実行しようとして、エラーになってしまったりするので、Ramp Upでたとえば200秒を指定しておくと、1秒間に1ユーザーずつログインしていくようにコントロールできるようになります。 また、徐々にアクセス数が増えていきピークに達する様子を再現するのにも使えます。 |
Run Now | すぐに負荷試験を開始する場合に選びます |
Run on Schecule | 指定したスケジュールで開始したい場合はこちらを選びます |
Include Live Data | 選択すると、実行中にリアルタイムでデータの推移を見ることができます |
右側には、シナリオを決めるための項目があります。
今回はTest TypeをJMeterにしていますが、他に以下のように Single HTTP Endpoint
を選ぶこともできます。こちらも非常に便利で、エンドポイントを一つだけの固定にはなってしまいますが、HTTPメソッドや、HTTPヘッダー、リクエストBodyなどを指定して負荷をかけることができます。
JMeterを選ぶと以下のように jmx
ファイルか、複雑なシナリオになるとjmxから呼ばれるcsvなども含みたい場合があるので、それらをzipしたファイルをアップロードすることができます。
JMeterでやったこと
インストール
- JMeterをインストール
$ brew install jmeter
- JMeterをコマンドで起動
$ jmeter
シナリオを書く
言語を日本語にしています
定数スループットタイマを設定する
追加 > タイマ > Constant Throughput Timer
ターゲットスループット(サンプル数/分): 60.0
Calculate Throughput based on: all active threds
に設定することで、このJMeterシナリオ全体で1秒間に1リクエストに制限された負荷をかけることができるようになります。
ログインを実装する
- ログインアカウントのCSVを作成する
以下のように実在するユーザーのログイン情報であるemailとpasswordのcsvデータを用意します。
user1@example.com,hogehoge1
user2@example.com,hogehoge2
user3@example.com,hogehoge3
-
CSVを読み込んで変数に設定する
追加 > 設定エレメント > CSV Data Set Config
Variable Namesにカンマ区切りで変数名を指定します。email,password
-
ユーザー定義変数を追加して、認証後に受け取る認証トークンを格納する変数を宣言する
追加 > 設定エレメント > ユーザー定義変数
名前にtoken
、値は後から入れるので何も設定しません。 -
一度だけ実行されるコントローラを追加
追加 > ロジックコントローラ > 一度だけ実行されるコントローラ
この中に追加したサンプラーは、スレッドごとにループしている時でも一度だけしか実行されません。 -
中にHTTP リクエストのサンプラーを追加
追加 > サンプラ > HTTP リクエスト
-
ログインリクエストのBody DataにJSONでログイン情報を設定していますが、変数で定義しておいた、emailとpasswordを呼び出しています。
スレッドが呼び出されるたびにcsvの上から順番に変数がセットされていくため、別のアカウントでログインすることができるようになります。 -
認証後のJSONレスポンスの中にidTokenというトークンが返されるので、後処理を追加して変数tokenに格納する。
追加 > 後処理 > JSON Extractor
Names of created variables: token
JSON Path expressions: idToken
-
HTTP ヘッダマネージャでヘッダーにトークンをセットする
設定エレメント > HTTP ヘッダマネージャ
名前:Authorization、値: Bearer ${token}
名前:Content-Type、値: application/json
-
以降に追加するHTTP リクエストサンプラーは、ヘッダーにトークンがつきますので、APIの認証を通過できるようになります。
JMeterは他にもランダムコントローラや、CSVのURLリストを呼び出したり色々なことができますが、全てを書くことができないので割愛します。
思い通りのスループットで負荷をかけるための設定
1秒間に何リクエストの負荷をかけたいかを決めて負荷をかける場合の設定方法です。
たとえば1秒間に200リクエストの負荷をかけるとします。
200/rpsは、かなりの負荷なのでタスク数はそれなりに必要になると思います。厳密に全パターンを試してみたわけではないのですが、200/rpsを10タスクで試したときは、期待した負荷の半分ほどしかスループットが出ませんでしたが、140/rpsを20タスクで試したときは、期待通りの負荷をかけきることができました。
計算しやすいように、200/rpsを20タスクで実施するとした場合、1タスクあたり20/rpsをかけられればよいので、1分間に換算すると120/分になります。
なのでJMeterの一番最初に設定した定数スループットタイマの
ターゲットスループット(サンプル数/分)
という項目に 120.0
を設定します。
JMeterでターゲットスループットを設定していれば、DLTのConcurrencyを増やしたとしても全体のスループットには影響しませんでした。仮想ユーザーを増やしても合計のスループットを守ってくれるので、アクセスが多くなってしまうことがありませんでした。
JMeter側でやらない負荷設定について
DLTでも設定できるし、JMeterでも設定できる項目があり、どちらに設定したらよいのか迷った設定がありました。
JMeterはスレッドグループごとに、 スレッド数
RampUp
ループ回数
を設定できます。ただ今回は、DLTでもこれをコントロールできるので、タスク数を増やした時でも事前に負荷を計算しやすいように、全てDLTでやることにして、JMeterではこれらの値を全て1にしました。
DLTでコントロールする場合は、それぞれ以下を設定する感じです。
スレッド数=Concurrency
Ramp-Up=RAMP UP
ループ回数=Fold For(DLTは回数ではなく時間で指定する)
結果レポートについて
DLTでの負荷試験が終了するとすぐに、レポートが表示されます。このレポートはweb上でログインすればいつでもみられるので、共有が簡単でいいです。項目も必要十分でした。以下の画像には出ていませんが、JMeterのシナリオでHTTPリクエストにわかりやすい名前( 一覧表示
、 詳細表示
)などをつけておけば、各HTTPリクエスト毎の負荷を見られました。
その他JMeterでできること
JMeterでは、ブラウザのプロキシとしてJMeterを通すことでユーザーが行ったブラウザ操作を記録してくれる機能などもあります。ある程度決まりきったシナリオを何度も流すような場合は、便利な機能だと思います。
他には、数万件のページのリストをCSVで持たせておき、均等にアクセスさせるといったこともできました。
精密なスループット設定などもあったり、かなり細かな要件にも対応できるようです。
まとめ
DLTは簡単で気に入っているのですが、JMeterはドキュメントがとても読み辛くて覚えるのに苦労しました。
慣れてしまえば、なんでも出来て面白いです。残った課題としては、リクエストした結果から値を取り出して、次のリクエストで使うシナリオを実施してみた時に気づいたのですが、負荷が高いと当然レスポンスを返せない場合があるので、後続のリクエストが全てエラーになってしまうという問題があり、負荷以外でのエラーが多く出てしまいました。
レスポンスによって内容を変えていく場合は、エラーハンドリングまで考えないといけないなと思いました。
おおむねやりたいことは、カバー出来そうだという感想でして、今後も使っていきたいと思っています。
Discussion