負荷試験テストツールGatlingの使い方

# はじめに
負荷試験でテストツールGatlingを初めて使用したので、インストールからGatling実行結果を確認するまでの手順をまとめました。

# インストール手順
### OpenJDKのインストール  
GatlingはScalaによって書かれており、JavaVM上で動作します。そのため、実行するにはJavaVMのインストールが必要です。

[Oracle公式サイト](https://www.oracle.com/technetwork/java/javase/downloads/index.html)からJDKをダウンロード、インストールします。
[Gatling公式](https://gatling.io/docs/current/installation/)によると、64bit版のJDK8、JDK11以外のバージョンはサポート対象外のようです。
この記事ではJDK8をインストールして動作確認しています。

インストール後、以下のコマンドを実行し、Javaのバージョンが表示されていればインストール完了です。

```
java -version
```

### Gatlingのインストール  
[Gatling公式サイト](https://gatling.io/)からzipパッケージをダウンロードし、解凍します。

コマンドでも取得できます。

```
# ダウンロード
wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.1.3/gatling-charts-highcharts-bundle-3.1.3-bundle.zip

unzip gatling-charts-highcharts-bundle-3.1.3-bundle.zip
```
# 動作確認
インストールが完了したらGatlingが実行できるようになっていることを確認します。
解凍したフォルダに移動し、以下を実行します。

Linux/Unixの場合

```
bin/gatling.sh
```
Windowsの場合

```
bin/gatling.bat
```

このように表示されれば、Gatlingを実行できる状態です。

```
GATLING_HOME is set to /Users/hoguchi/gatling-charts-highcharts-bundle-3.3.1

Choose a simulation number:
     [0] computerdatabase.BasicSimulation
     [1] computerdatabase.advanced.AdvancedSimulationStep01
     [2] computerdatabase.advanced.AdvancedSimulationStep02
     [3] computerdatabase.advanced.AdvancedSimulationStep03
     [4] computerdatabase.advanced.AdvancedSimulationStep04
     [5] computerdatabase.advanced.AdvancedSimulationStep05
```

0を入力し、computerdatabase.BasicSimulationを実行します。
```Select run description (optional)```と表示されたらEnterを押すと、BasicSimulationに定義された負荷試験のシナリオが実行されます。

実行中は試験の途中経過が表示され、試験が終わると試験結果が表示されます。

```
================================================================================
---- Global Information --------------------------------------------------------
> request count                                         13 (OK=13     KO=0     )
> min response time                                    248 (OK=248    KO=-     )
> max response time                                   1204 (OK=1204   KO=-     )
> mean response time                                   450 (OK=450    KO=-     )
> std deviation                                        254 (OK=254    KO=-     )
> response time 50th percentile                        354 (OK=354    KO=-     )
> response time 75th percentile                        454 (OK=454    KO=-     )
> response time 95th percentile                        910 (OK=910    KO=-     )
> response time 99th percentile                       1145 (OK=1145   KO=-     )
> mean requests/sec                                  0.464 (OK=0.464  KO=-     )
---- Response Time Distribution ------------------------------------------------
> t < 800 ms                                            12 ( 92%)
> 800 ms < t < 1200 ms                                   0 (  0%)
> t > 1200 ms                                            1 (  8%)
> failed                                                 0 (  0%)
================================================================================
```
- response time XX percentile:計測したデータをレスポンスタイムの小さい順に並べたときに、全体のXX%に位置するレスポンスタイム(ms)
- mean requests/sec:秒間あたりに処理したリクエスト数の平均値
- KOはNGの意
- Response Time Distributionのレスポンスタイム境界値(800ms、1200ms)や、response time XX percentileのパーセンタイル値はconfフォルダのgatling.confから変更できます。値を変更した箇所はコメントを外さないと反映されないので注意。

試験結果はresultsフォルダに保存されます。htmlファイルを開くと、グラフ化された試験結果を確認することができます。
![Gatling_BasicSimulation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392897/0735c0de-48b2-e826-5e4c-8cd06ecfec01.png)

# 独自シナリオの作成
user-files/simulations/computerdatabaseに負荷試験のシナリオを定義したファイルを作成します。シナリオはsetUp内に定義します。
この例はbaseURLに指定したテスト対象のURLに対してGETリクエストを5秒間10ユーザが投げ続けるシナリオです。

```scala:SampleSimulation.scala

package computerdatabase

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._

class SampleSimulation extends Simulation {
  val httpProtocol = http
    .baseUrl("http://localhost:5000")
    .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
    .doNotTrackHeader("1")
    .acceptLanguageHeader("en-US,en;q=0.5")
    .acceptEncodingHeader("gzip, deflate")
    .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")

  val scn = scenario("SampleScenario")
    .exec(http("request_1")
      .get("/")
      .check(status.is(200))) //HTTPステータスが200か否かをチェックする

  //シナリオを定義
  setUp(
    scn.inject(rampUsers(10) during(5 seconds)) .protocols(httpProtocol)
  )
}
```

HTTPステータスをチェックすることもできます。
```.check(status.is(200)))```

200以外のHTTPステータスが返ってきた場合は、ErrorsにHTTPステータスが表示されます。

```
================================================================================
---- Global Information --------------------------------------------------------
> request count                                        618 (OK=617    KO=1     )
> min response time                                     42 (OK=42     KO=1051  )
> max response time                                   1051 (OK=429    KO=1051  )
> mean response time                                   154 (OK=153    KO=1051  )
> std deviation                                         54 (OK=40     KO=0     )
> response time 50th percentile                        152 (OK=152    KO=1051  )
> response time 75th percentile                        167 (OK=167    KO=1051  )
> response time 90th percentile                        183 (OK=183    KO=1051  )
> response time 99th percentile                        395 (OK=387    KO=1051  )
> mean requests/sec                                 56.182 (OK=56.091 KO=0.091 )
---- Response Time Distribution ------------------------------------------------
> t < 1000 ms                                          617 (100%)
> 1000 ms < t < 1500 ms                                  0 (  0%)
> t > 1500 ms                                            0 (  0%)
> failed                                                 1 (  0%)
---- Errors --------------------------------------------------------------------
> status.find.is(200), but actually found 500                         1 (100.0%)
================================================================================
```

setUp()内に定義できるシナリオは他にもあります。

| シナリオ       　　    | 説明               |
|:---------------------|-------------------|
| nothingFor(5 seconds)| 指定した時間、一時停止する |
| atOnceUsers(10) | 指定したユーザ数での同時アクセスを一回行う |
| rampUsers(10) during(5 seconds) | 指定した時間で、指定したユーザ数のアクセスが線形に立ち上がる。左の例だと、5秒間で10ユーザが立ち上がる（総リクエスト数は10） |
| constantUsersPerSec(20) during (15 seconds) | 指定した時間、1秒ごとに指定したユーザ数が立ち上がる。左の例だと、15秒の間、秒間20ユーザが立ち上がる（総リクエスト数は300）|
| constantUsersPerSec(20) during (15 seconds) randomized | 指定した時間、1秒ごとに指定したユーザ数が立ち上がるが、ユーザの立ち上がりの間隔がランダムになる |
| rampUsersPerSec(10) to 20 during (10 minutes) | 指定した時間の間で、指定した開始時の秒間ユーザ数から終了時の秒間ユーザ数まで一定の間隔で上げていく。左の例だと、開始時は秒間10ユーザが立ち上がるが、一定の間隔で秒間ユーザ数を上げ、終了時には秒間20ユーザが立ち上がっている状態 |
| rampUsersPerSec(10) to 20 during (10 minutes) randomized | 指定した時間の間で、指定した開始時の秒間ユーザ数から終了時の秒間ユーザ数まで上げていくが、上げていく間隔がランダムになる |
| constantConcurrentUsers(10) during (10 seconds) | 指定した時間、同時にアクセスしてくるユーザ数を指定した数に制限する。左の例では、同時にアクセスできるユーザ数は最大10まで|
| rampConcurrentUsers(10) to (20) during (10 seconds) | 指定した時間の間で、同時にアクセスしてくるユーザ数の最大値を指定した開始時の値から終了時の値まで上げていく。左の例だと、開始時の同時にアクセスできるユーザ数は最大10だが、終了時には20ユーザが最大になる|

# 参考URL
- [Gatling公式](https://gatling.io/docs/current/installation/)
- [便利すぎる負荷試験テストツールGatlingの使い方~自力ソース編~ \- Qiita](https://qiita.com/nii_yan/items/d7d0ea949abeab13aea7)
- [Gatling \| 負荷設定の種類とユーザの立ち上がり方について – ムッシューのＩＴ備忘録](https://mussyu1204.myhome.cx/wordpress/it/?p=397)