CLOVER🍀

That was when it all began.

負荷テストツール、Gatlingで遊んでみる

最近ちょっと目にした負荷テストツール、Gatlingをちょっと試してみました。

Gatling
http://gatling-tool.org/

Apache JMeterのような負荷テストツールらしいのですが、

  • テストシナリオをScalaDSLで書ける
  • レポートがHTMLで出力される
  • シナリオ作成ツールが付属している

みたいな特徴があるみたいです。パフォーマンスが良いという話もあるらしいのですが、最近はJMeterも頑張っているそうです。

自分としては、普段こういう負荷テストツールは使っていない(JMeter面倒そうだし…)ので、DSLで書けるようなツールは魅力的ですね。

1系と開発中の2系があるみたいで、今回は2系を使うことにします。

ドキュメントとしてはWikiを見るのですが…

User Document
https://github.com/excilys/gatling/wiki

内容的には、1系の書き方が混じっているっぽいので、そのあたりはダウンロードしたファイルについてくるサンプルを見ながら読み替えていくのがよいでしょう。

参照したドキュメントは、以下になります。

Getting Started
https://github.com/excilys/gatling/wiki/Getting-Started

First Steps with Gatling
https://github.com/excilys/gatling/wiki/First-Steps-with-Gatling

日本語のサイトでは、こちらが非常に参考になりました。

負荷テストツール「Gatling」を使ってみよう。
http://blog.udcp.net/2013/10/07/gatling-stress-tool/

インストール

では、まずはGatlingをインストールします。事前に要求されるのは、JDKがインストールされていることです。あとは、アーカイブをダウンロードしてきて展開するだけ。

$ tar -zxvf gatling-charts-highcharts-2.0.0-M3a-bundle
.tar.gz

今回はtar.gzをダウンロードし、バージョンは2.0.0-M3aを選択しました。

インストールは、これだけです。

あと、サンプルプログラムが

gatling-charts-highcharts-2.0.0-M3a/user-files/simulations

ディレクトリ配下に入っているので、目を通すとよいでしょう。

こんな感じです。

$ find gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/ -type f
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/basic/BasicExampleSimulation.scala
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/advanced/SomeOtherScenario.scala
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/advanced/SomeScenario.scala
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/advanced/Headers.scala
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/advanced/AdvancedExampleSimulation.scala

シナリオを書いてみる

では、負荷テストシナリオを書いてみましょう。テスト対象は…手元に手頃なものがなかったので、まずはJBoss AS 7のトップページにしました。

$ jboss-as-7.1.1.Final/bin/standalone.sh

作成するシナリオは、以下のディレクトリ配下にScalaソースコードとして作成します。

gatling-charts-highcharts-2.0.0-M3a/user-files/simulations

今回は、こんなシナリオを作成しました。
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/GettingStartedSimulation.scala

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
import io.gatling.http.Headers.Names._
import scala.concurrent.duration._
import bootstrap._
import assertions._

class GettingStartedSimulation extends Simulation {
  val httpProtocol =
    http
      .baseURL("http://localhost:8080")
	  .acceptCharsetHeader("ISO-8859-1,utf-8;q=0.7,*;q=0.7")
	  .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
	  .acceptEncodingHeader("gzip, deflate")
	  .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3")
	  .disableFollowRedirect

  val scn =
    scenario("Getting Started Scenario")
      .exec {
        http("simpleRequest")
          .get("/")
          .check(status.is(200))
      }

  setUp(scn.inject(ramp(1000 users) over (50 seconds)))
    .protocols(httpProtocol)
    .assertions(global.successfulRequests.percent.is(100))
}

単純に、トップページにアクセスするシナリオです。ステータスコードが200であることを、シナリオ中で定義しています。

シナリオは、作成したScalaのクラス名で実行時に選びます。また、

        http("simpleRequest")

で付けた名前が、結果レポートに現れます。

負荷は、1000人のユーザが50秒でかけていきます。つまり、秒20人。そして、リクエストはひとりあたり「http://localhost:8080/」への1回なので、計1000回のリクエストが実行されるということになります。

  setUp(scn.inject(ramp(1000 users) over (50 seconds)))
    .protocols(httpProtocol)
    .assertions(global.successfulRequests.percent.is(100))

assertionsはなくてもいいみたいですが、100%成功リクエストが受け取れていること、を入れておきました。

実行する

それでは、書いたシナリオを実行してみます。

$ gatling-charts-highcharts-2.0.0-M3a/bin/gatling.sh
GATLING_HOME is set to /xxxxx/gatling-charts-highcharts-2.0.0-M3a

作成したScalaソースコードコンパイルが行われるようで、けっこう重たいです…。また、コンパイルできないシナリオを入れてしまうと、例外を投げてコケてしまいます。

で、起動するとシナリオを選択するように聞かれるので

Choose a simulation number:
     [0] GettingStartedSimulation
     [1] TransitionSimulation
     [2] advanced.AdvancedExampleSimulation
     [3] basic.BasicExampleSimulation

ここでは、「0」と入力。
*[1]と出ているのは、後で作成したシナリオです…

0

あとはEnterを押していくと

Select simulation id (default is 'gettingstartedsimulation'). Accepted characters are a-z, A-Z, 0-9, - and _

Select run description (optional)

Simulation GettingStartedSimulation started...

シナリオが実行されます。

================================================================================
2013-12-28 18:46:04                                           0s elapsed
---- Getting Started Scenario --------------------------------------------------
[                                                                          ]  0%
          waiting: 1000   / running: 0      / done:0     
---- Requests ------------------------------------------------------------------
> Global                                                   (OK=0      KO=0     )

================================================================================

進捗状況がこのまま表示されていき、終了するとこんなレポートが出ます。

Simulation finished.
Parsing log file(s)...
Parsing log file(s) done
Global percentage of requests OK is equal to 100 : true
Simulation successful.
Generating reports...

================================================================================
---- Global Information --------------------------------------------------------
> numberOfRequests                                    1000 (OK=1000   KO=0     )
> minResponseTime                                        0 (OK=0      KO=-     )
> maxResponseTime                                     1010 (OK=1010   KO=-     )
> meanResponseTime                                      16 (OK=16     KO=-     )
> stdDeviation                                          84 (OK=84     KO=-     )
> percentiles1                                          20 (OK=20     KO=-     )
> percentiles2                                         500 (OK=500    KO=-     )
> meanNumberOfRequestsPerSecond                         20 (OK=20     KO=-     )
---- Response Time Distribution ------------------------------------------------
> t < 800 ms                                           996 ( 99%)
> 800 ms < t < 1200 ms                                   4 (  0%)
> t > 1200 ms                                            0 (  0%)
> failed                                                 0 (  0%)
================================================================================

Reports generated in 0s.
Please open the following file : /xxxxx/gatling-charts-highcharts-2.0.0-M3a/results/gettingstartedsimulation-20131228184602/index.html

最後に、レポートがファイルに出たよと言っているので

Please open the following file : /xxxxx/gatling-charts-highcharts-2.0.0-M3a/results/gettingstartedsimulation-20131228184602/index.html

見てみます。

リクエストに付けた名前(今回は「simpleRequest」)を選択すると、そのリクエストに特化した情報も見れます。

すごい…。

その他、同ディレクトリにログやコンソールに出力された情報もファイルとしてできているので、確認するといいでしょう。

simulation.log
stats.tsv

シナリオ中で複数のリクエストを実行する

今度は、ひとつのシナリオで複数のリクエストを実行してみます。
gatling-charts-highcharts-2.0.0-M3a/user-files/simulations/TransitionSimulation.scala

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
import io.gatling.http.Headers.Names._
import scala.concurrent.duration._
import bootstrap._
import assertions._

class TransitionSimulation extends Simulation {
  val httpProtocol =
    http
      .baseURL("http://localhost:8080")
	  .acceptCharsetHeader("ISO-8859-1,utf-8;q=0.7,*;q=0.7")
	  .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
	  .acceptEncodingHeader("gzip, deflate")
	  .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3")
	  .disableFollowRedirect

  val scn =
    scenario("Transition Simulation")
      .repeat(5) {
        exec {
          http("indexRequest")
            .get("/")
            .check(status.is(200))
        }.pause(0 milliseconds, 100 milliseconds)
      }.exec {
        http("documentationRequest")
          .get("/documentation.html")
          .check(status.is(200))
      }

  setUp(scn.inject(ramp(1000 users) over (50 seconds)))
    .protocols(httpProtocol)
    .assertions(global.successfulRequests.percent.is(100))
}

アクセス先は、やっぱりJBoss AS 7のトップページと、そこから辿れる「documentation.html」にしました…。

トップページには5回アクセスし、その後ドキュメントページにアクセスします。また、ユーザー数は1000人が50秒かけてアクセスしてくるので、6000リクエストが実行されることになりますね。

で、今回は1を選択。

Choose a simulation number:
     [0] GettingStartedSimulation
     [1] TransitionSimulation
     [2] advanced.AdvancedExampleSimulation
     [3] basic.BasicExampleSimulation
1

さっき、最初のシナリオを書いた時に見えていたのは、これです…。

結果は、このように。

Simulation finished.
Parsing log file(s)...
Parsing log file(s) done
Global percentage of requests OK is equal to 100 : true
Simulation successful.
Generating reports...

================================================================================
---- Global Information --------------------------------------------------------
> numberOfRequests                                    6000 (OK=6000   KO=0     )
> minResponseTime                                        0 (OK=0      KO=-     )
> maxResponseTime                                      110 (OK=110    KO=-     )
> meanResponseTime                                       4 (OK=4      KO=-     )
> stdDeviation                                           6 (OK=6      KO=-     )
> percentiles1                                          10 (OK=10     KO=-     )
> percentiles2                                          20 (OK=20     KO=-     )
> meanNumberOfRequestsPerSecond                        119 (OK=119    KO=-     )
---- Response Time Distribution ------------------------------------------------
> t < 800 ms                                          6000 (100%)
> 800 ms < t < 1200 ms                                   0 (  0%)
> t > 1200 ms                                            0 (  0%)
> failed                                                 0 (  0%)
================================================================================

Reports generated in 0s.
Please open the following file : /xxxxx/gatling-charts-highcharts-2.0.0-M3a/results/transitionsimulation-20131228190301/index.html

結果は、全体と

リクエストごとに確認できます。
indexRequest

documentationRequest

なかなか便利です。他にも、シナリオをまとめて実行することもできるみたいです。詳しくは、サンプルを…。

Scalaでシナリオを書くが故に、ちょっとコンパイルが重たいのが難点ですが、使えるところには活用したいと思います。