JMeterで負荷テスト

こんにちわ、TenForward こと加藤です。

[ファーストサーバ Advent Calendar 2015](http://qiita.com/advent-calendar/2015/firstserver) 4 日目の記事ですな。

新規サービスをリリースする際などに負荷テストを行う必要があると、なぜか私のところに話が来ます。

そこで、そのような場合にどういう風にテストを行っているかを簡単に紹介してみたいと思います。

最近はPythonで書かれた[Locust](http://locust.io/)というツールにも興味があるのですが、残念ながら私はPythonを自在に扱えないので、昔から使っている[Apache JMeter](http://jmeter.apache.org/)を使っています。まだまだJMeterを使っている人は多いのか、私が2008年に書いたほぼメモ代わりのブログエントリにもかなりのアクセスがあります。

ファーストサーバで負荷テストを行う場合、以下のようなケースがあります。

* サービスで提供するWebアプリケーションが想定する負荷に耐えられるか?
* ホスティングサービスを提供する場合、設定したリソースでどの程度の負荷まで耐えられるか?

前者の場合、[Zenlogic](https://zenlogic.jp/)ではコンパネを提供していますので、多数のお客様が同時にコンパネを使った場合に想定する負荷に耐えられるか、というようなテストです。

後者の場合、[Zenlogic](https://zenlogic.jp/)では提供するCPUやメモリリソースに応じて、プラン1からプラン7までが存在します。それぞれのプランで、契約されるお客様が従業員何人くらいという想定がありますので、その人数がどれくらいの頻度でWebやメールを使うかという想定に基づいて負荷をかけます。逆に、想定がなくて、どれくらいまでいけるのかを見極めるためにテストを行う場合もあります。

# テストプランの作成

テストプランの作成は特に変わったことをしてるわけではなく、JMeterのGUIを起動して以下のような手順で作成しています。

1. JMeterの「HTTPプロキシサーバ」を起動する
1. JMeterの「HTTPプロキシサーバ」経由で、テスト対象のサーバにリクエストを送ってリクエストを記録する
1. 記録したリクエストのうち、毎回変化するような部分を調整する
1. リスナーとして「結果をツリーで表示」を追加し、調整したテストプランでリクエストを送り、結果を見る

あとは 3 と 4 の繰り返しでテストプランを仕上げて行きます。通常 JMeter でテストプランを作成する場合によく使われる手順ではないかと思います。

# テスト実行用のシェルスクリプトの作成

テストを実行する場合、JMeterをGUIで起動してテストを行うわけではありませんし、毎回パラメータで調整する部分もありますので、JMeterを起動するためのシェルスクリプトを作成しています。

オプションを受け付けるようにしていますので、自分で作ったスクリプトとはいえ、オプションを忘れてもスクリプトの中身を見なくて住むようにヘルプもつけたりします。例えば以下のような風にしています。

```sh
$ ./ZenlogicAddVM.sh -h

usage: ZenlogicAddVM.sh [options...]

Run the test of creating VM using apache jmeter.
  -C / --cui                    non-GUI mode
  -T / --logtype                log type (xml or csv) when non-GUI mode
    :(略)
  -r / --rampup=SECOND          ramp-up time (sec)
  -p / --throughput=NUM         throughput (per min)
    :(略)
```

ここでオプションでループ回数や同時アクセスユーザ数などを設定できるようにしています。

# テストプランへ変数を渡す

テスト条件を設定するのは、前述のようにシェルスクリプトのオプションで与えますが、それをJMeterに渡す際にはJMeterのプロパティを使います。

JMeterのオプションで`-J`を使うと、JMeterのプロパティと値を設定できます。例えば、

```
jmeter -J Loop=10
```

と実行すると、"Loop"というプロパティに10が設定されます。このプロパティは、テストプラン中では`${__P(プロパティ名)}`で参照できます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/27073/a9ca7fe1-8e0f-b8f1-35b5-b17177e991fb.png)

# ファイルから変数に値を与える

テストでは、同時に発生させるスレッドごとに値を変えたり、ループのたびに値を変えたりしたい変数もあるでしょう。例えば、

* ユーザ名、パスワード
* マルチテナントの場合のアクセス先のサーバ

のような場合です。

CSVファイルとして

```
user01,password
user02,password
```

以上のようなファイルを`user.csv`として準備した場合、

![2.png](https://qiita-image-store.s3.amazonaws.com/0/27073/ec93942d-eddd-c044-51e1-a7a80b59183f.png)

以上のように設定すると、スレッドごとに1行目から順に行を読み込んで、`user`という変数に1番目のカラムの値を、`pass`という変数に2番目のカラムの値を入れてくれます。ファイルの最後までいったら、最初の行に戻ってくれます。

この変数は`${user}`、`${pass}`のように参照できます。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/27073/ffd2c8fb-faa6-c1b6-0830-281661e04e06.png)

# テストの実行

テストを実行する際はGUIでなくCUIモードでJMeterを起動します。CUIモードは`-n`ですね。

```
jmeter -n -t TestPlan.jmx -Djmeter.save.saveservice.output_format=csv -l loadtest_result.csv
```

テストプランは`-t`で指定します。結果を出力ファイルは`-l`で指定します。

`jmeter.save.saveservice.output_format`に`csv`を設定すると結果をCSV形式で、`jtl`を設定するとXML形式で出力してくれますね。

出力したファイルはGUIモードでリスナーでグラフ表示させたり、統計処理させて表で表示させたり、自分でパースしてグラフ化したりしています。

# まとめ

JMeter で負荷テストを行う際の、テストプランの作成の大まかな流れと、テストプラン全体に条件与える方法、JMeter の起動方法について書いてみました。

* テストプランを作成するときに「HTTPプロキシサーバ」経由でアクセスをしてみてテストプランのベースを作成する
* JMeter に色々パラメータを与えるためにシェルスクリプトを作成し、変数をオプションで与えられるようにする
* JMeter のプロパティを使ってテストプランに変数を渡す
* ファイルから JMeter のテストプランの変数に値を渡す
* JMeter の CUI モードでの実行

もちろん、テストプランの細かなところで色々な設定を行う必要があるので、今回書いたことだけではテストは実行できませんが、何かの参考になれば。