Scala 初心者が Gatling をぶっ放して負荷テストをやってみました

このエントリーをはてなブックマークに追加
みなさま、こんにちは! munepom です。
最近、負荷テストツールの Gatling を使い始めましたので、ちょっと記事にしておきます。

事の発端は、先月の JJUG ナイトセミナーにて。
Apache JMeterがめっちゃdisられていました
Gatling という負荷テストツールが Apache JMeter よりも良いのではないか?と紹介されていました。

どんなものかと思い、調べてみると、、、、、、
レポート画面が見やすいですね!
応答時間の分布や、同時実行ユーザ数あたりの応答時間の分布などなど。
これは使ってみたい!と思い、いざセットアップを行ったわけです。
が...
これ、Scala の DSL でシナリオを書くんですね。
自分、Scala 開発未経験なのですが。
大丈夫でしょうか...

まあ、Web で情報集めれば何とかなるでしょ!
ということで、実質 1 日、試行錯誤した末のセットアップ手順です。

IntelliJ IDEA CE 14.1.5 + sbt 0.13.9 + Gatling 2.1.7 という構成で、
sbt test 実行により負荷テストを行う場合です。
(Windows 7 Professional と、Mac OS X Yosemite にて確認しました)
(一応、Eclipse + Scala IDE + Gradle という構成でも実行できたのですが、sbt を利用した方法を書いておきますね。)

1. sbt (Simple Build Tool) インストール

最終的に Terminal で sbt を実行するため、事前にインストールしておきました。
Windows の場合は、.msi ファイルを実行するとインストールできました。
Mac の場合は、homebrew でインストールすることもできますが、
このブログを書いている段階では、バージョン 0.13.7 と古いバージョンでしたので、
Installing sbt manually を参考に、0.13.9 を手動でインストールしておきました。

2. IDE (統合開発環境) インストール

Scala 開発の IDE といえば、IntelliJ IDEA
ということで、無料版の Community Edition をダウンロードして、インストールしました。
※ インストール後は、下記設定を行いました。
  1. Configure → Plugins → Browse repositories より、Scala をインストールしました (IntelliJ インストール時に行っても良いですね)。
  2. Configure → Project Defaults → Settings → Editor → File Encodings にて、Project Encoding と Default encoding for properties files を設定しておくと、後で幸せになれると思います。
  3. Configure → Project Defaults → Settings → Build, Execution, Deployment → SBT → Launcher (sbt-launch.jar) にて、Custon を選択し、インストール済みの sbt-launch.jar のパスを指定しました。
  4. Configure → Project Defaults → Project Structure → Platform Settings → SDKs にて、緑色の + を選択し、JDK を選択しておきました。

3. SBT プロジェクト作成

IntelliJ 起動後、Create New Project -> Scala -> SBT を選択し、
Project name に適当なプロジェクト名を入力しました。(今回は、GatlingIdea としておきました。)
Finish を選択し、プロジェクト管理画面が開かれた後、Refresh 完了を待ちました。
※ こんなエラーログが出るかもですが、気にせず .sbt 設定へ進みましょう。
11:47:07 SBT project import
         [warn]  [FAILED     ] org.scala-sbt#compiler-interface;0.13.8!compiler-interface.jar(src):  (0ms)
         [warn] ==== typesafe-ivy-releases: tried
         [warn]   https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/0.13.8/srcs/compiler-interface-sources.jar
         [warn] ==== sbt-plugin-releases: tried
         [warn]   https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/org.scala-sbt/compiler-interface/0.13.8/srcs/compiler-interface-sources.jar
         [warn] ==== local: tried
         [warn]   C:\Users\hogehoge\.ivy2\local\org.scala-sbt\compiler-interface\0.13.8\srcs\compiler-interface-sources.jar
         [warn] ==== public: tried
         [warn]   https://repo1.maven.org/maven2/org/scala-sbt/compiler-interface/0.13.8/compiler-interface-0.13.8-sources.jar
         [warn]  ::::::::::::::::::::::::::::::::::::::::::::::
         [warn]  ::              FAILED DOWNLOADS            ::
         [warn]  :: ^ see resolution messages for details  ^ ::
         [warn]  ::::::::::::::::::::::::::::::::::::::::::::::
         [warn]  :: org.scala-sbt#compiler... (show balloon)
※ compiler-interface.jar は、sbt コマンド実行時に作成されるようでしたので。(おそらく、sbt 実行時に Scala バージョンをチェックし、動的に変更できるようにしてあるのでしょう。)

4. .sbt 設定

※ Gatling のバージョンにより、設定方法が変わる可能性がありますので、公式サイトを確認してください。
build.sbt
// "Expression Type (DslEntry) must conform to Setting[_] in SBT file" という警告が出ますが、気にしないでおきます。
// Stack Overflow でも、解決策見つからず...
enablePlugins(GatlingPlugin)

name := "GatlingIdea"

version := "1.0"

scalaVersion := "2.11.7"

// DNS の TTL を 0 にしたい場合など、Java のオプションを指定可能なようです。
// SSL の証明書チェックは、Gatling では行われないようなので、SSL 証明書チェックを無視する場合の -Djsse.enableSNIExtension=false 設定はいらない?
// javaOptions in Gatling := overrideDefaultJavaOptions("-Xms1G", "-Xmx2G", "-Dsun.net.inetaddr.ttl=0")

libraryDependencies ++= Seq(
  "io.gatling.highcharts" % "gatling-charts-highcharts" % "2.1.7" % "test",
  "io.gatling"            % "gatling-test-framework"    % "2.1.7" % "test"
)
project/plugins.sbt
logLevel := Level.Warn

addSbtPlugin("io.gatling" % "gatling-sbt" % "2.1.7")
ここまで完了したら、一旦、Project Refresh を実行しておきました。
(View → Tool Windows → SBT で開かれる画面の回転矢印アイコンを選択すると、実行されました。)

5. テスト用ソースコード作成

src/test/scala-2.11 ディレクトリに gatling.simulations パッケージを作成後、
TestIdea.scala ファイルを作成しました。
TestIdea.scala
package gatling.simulations

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

class TestIdea extends Simulation {
  // URL の最後に "/" を付けると、テストが通りまへん
  val httpLocal = http.baseURL("http://localhost")

  // Header 設定も可能っぽいです
  val httpDev   = http
    .baseURL("http://dev-localhost")
    .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 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0")

  var scn = scenario("Load Test").exec(http("Munepom").get("/munepom").check(status.is(200)))

  var scnCheckBody = scenario("Check Body")
    .exec(
      http("Add").get("/munepom/add")
        .check(
          // 不正な XML (???) だと、XPath 解析時に SAXParseException が発生しました
          // GHE にアクセスしてみた場合、こんなエラーログが
          ////////
          //  Error on line 49 column 67
          //  SXXP0003: Error reported by XML parser:
          //  要素タイプ"meta"に関連付けられている属性名"data-pjax-transient"の後には、' = '
          //文字が必要です。
          //15:56:03.297 [WARN ] i.g.h.a.AsyncHandlerActor - Request 'GHE Redirect 1' failed
          //: xpath(/html/head/meta[@name='csrf-param']/@content).find(0).exists failed, cou
          //ld not prepare: Could not parse response into a DOM Document: org.xml.sax.SAXPar
          //seException; lineNumber: 49; columnNumber: 67; 要素タイプ"meta"に関連付けられて
          //いる属性名"data-pjax-transient"の後には、' = '文字が必要です。
          ////////
          //        xpath("//input[@value='${aaaa_value}']/@id").saveAs("aaaa_id"),
          //        css("#hoge", "data-fuga").saveAs("id_hoge_data_fuga"),  // CSS セレクタが利用可能っぽいです
          //        regex("""<input id="HogeText" type="text" value="(.*)" />""").saveAs("hoge_text_value"), // 正規表現により、抽出も可能っぽいです
          //        bodyString.transform(string => string).saveAs("response_body") // response body を確認したい場合は、一旦 Session へ突っ込んでおきます
        )
    )
    .exec(session => { // Session オブジェクトに格納された情報を、key で参照できました
      //    println("--aaaa_id: " + session("aaaa_id"))
      //    println("--id_hoge_data_fuga: " + session("id_hoge_data_fuga"))
      //    println("--hoge_text_value: " + session("hoge_text_value"))
      //    println("--body: " + session("response_body"))
      session // これをお忘れなきよう (ハマりました...)
    })

  var scnFullThrottle = scenario("Full Throttle")
    .during(1 minute) { // wait 無しで打ち放題!
      exec(
        http("Stress Test").get("/stress/test"))
    }

  // setUp は、一度しか実行できません。内部に、シナリオをごっそり書くのはアリっぽいです
  setUp(
    scn.inject(atOnceUsers(2)).protocols(httpLocal), // 同時アクセス2ユーザ
    scnCheckBody.inject(atOnceUsers(2)).protocols(httpLocal),
    //    scnFullThrottle.inject(
    //          rampUsersPerSec(2) to(10) during(60 seconds), // 1秒あたりの同時アクセス2ユーザでアクセスを開始し、60秒間で10ユーザまで増やす
    //          constantUsersPerSec(10) during(60 seconds) // 1秒あたりの同時アクセス10ユーザで、60秒アクセスを行う
    // ).protocols(httpLocal),
    scnFullThrottle.inject(atOnceUsers(2)).protocols(httpDev)
  )
}

6. Gatling 発射!

IntelliJ の画面左下のランチャーより、Terminal を選択し、
Terminal に sbt test を入力後、
Enter を押して実行しました。
※ パッケージのダウンロード終了後、compiler-interface のコンパイルを確認できました。
...
[info] Compiling 1 Scala source to C:\Users\hogehoge\IdeaProjects\GatlingIdea\target\scala-2.11\test-classes...
[info] 'compiler-interface' not yet compiled for Scala 2.11.7. Compiling...
[info]   Compilation completed in 13.246 s
...
実行が完了すると、レポートが作成されます。
...
Reports generated in 1s.
Please open the following file: C:\Users\hogehoge\IdeaProjects\GatlingIdea\target\gatling\testidea-1444786144574\index.html
[info] Simulation TestIdea successful.
[info] Simulation(s) execution ended.
[success] Total time: 79 s, completed 2015/10/14 10:30:06

7. レポート確認

あとは、作成されたレポートをブラウザで表示するだけです!

Windows の場合は、Terminal で
start chrome "filepath"
を実行すると、Chrome で閲覧可能です。

Mac なら、Terminal で
open "filepath"
を実行すると、デフォルト設定のブラウザで閲覧できますね。

負荷テスト結果概要 (ソート可能っぽいです)

レスポンス時間の分布グラフ

レスポンス時間のパーセンタイルグラフ

レイテンシーのパーセンタイルグラフ

などなど。
グラフの拡大もできるので、便利です!
Qiita の情報や、めっちゃ役立つサンプルコードに助けられました。
ありがとうございます!
今夜の JJUG ナイトセミナーも楽しみですねん。

あ、※ DDoS 攻撃厳禁ですよーーー!
Enjoy!
次の記事
« Prev Post
前の記事
Next Post »
Related Posts Plugin for WordPress, Blogger...