S.Hayakawaをフォローする

Goで負荷テストを書きたい【locust + boomer】

バックエンド

こんにちは、Golangの記事5回目です。
今回は負荷テストのシナリオをGoで書く方法について書いていきます。

みなさんプロジェクトの負荷試験をするときはどうやっているのでしょうか?
私の現在のプロジェクトでは、負荷試験はGatlingというツールを使っていました。
https://github.com/gatling/gatling

こちらはテストスクリプトをscalaで記述するものだったので、
Goで負荷テストのシナリオを書く方法はないかな?と思い調べてみました。

そこで、locust + boomer の組み合わせが良さそうだったので、実際に動かして試してみました。
今回は、簡単に動作確認をするため、HTTPリクエストが行える最低限の骨組みを作っていきます!

Tools

Locustはイナゴという意味で、これ単体で負荷テストが書けるツールです。
言語はpythonで、負荷試験の際にmasterwokerという2つのアプリケーションを作成します。

boomerは、このうちworkerの方をGoで実装するためのライブラリです。
workerは実際に負荷をかける部分を担当し、テストシナリオなどを記述します。

Version

Locust: 2.15.1
Boomer: 1.6.1

Let’s Do This

実際にやっていきましょう。
今回は、簡単なHTTPサーバを立てて負荷テストを動かしてみます。
手順は大まかに以下です。

  • Locustのインストール
  • boomerのテストスクリプトを実装
  • テスト用にサーバを立てる(ご自身の環境がある場合は不要です。)
  • 実行する

Locustのインストール 

masterはLocustをそのまま起動させるので、pythonのpipコマンドでインストールする必要があります。 

コマンド
$ pip3 install locust

Locust Installation: document

また、Locustを動かすのに必要なので、Userクラスを実装したpythonファイルを
プロジェクトルートに追加します。
boomerの例と同じもので大丈夫です。 -> dummy.py
(ファイル名も同じ方がいいかもしれません。私はlocustのドキュメント通りに
locustfile.pyにしていたら、masterとwokerの接続がうまくいきませんでした。)

boomerのテストスクリプトを実装する

boomer/boomer.go

main()内ではタスクを作成して実行しています。
複数のタスクを作成することもできます。
boomer.Task{Fn: worker}ここで実行するシナリオを指定できます。

worker()にはシナリオを記述します。
内容としては、このあとに作成するローカルサーバへのリクエストを作成し、
成功/失敗と実行時間を記録しています。

テスト用にサーバを立てる

main.go

ping()ではランダムに1050msまでsleepしてからレスポンスを返すようにしてみました。
boomerのシナリオではリクエストのタイムアウトを1秒に設定しているので、
1000ms以上のsleepの場合はタイムアウトエラーが発生します。
これで失敗時の出力がどうなるのかも確認できそうです。

実行する

はじめに、main.goとboomer.goをビルドして実行ファイルを生成しておきます。

コマンド
$ go build -o a.out ./main.go
$ go build -o boomer ./boomer/boomer.go

実行後のディレクトリはこんな感じになります。

ディレクトリ構造
boomer
  L boomer (binary)
  L boomer.go
a.out (binary)
dummy.py
main.go

この他go.modなど

これで必要な材料が揃ったので実行していきます。

それぞれサーバ、locustのmasterアプリケーション、workerアプリケーションを起動します。

コマンド
$ ./a.out
$ locust --master -f dummy.py
$ ./boomer/boomer

これで準備が整いました。

Locustのweb UI

http://localhost:8089/
へアクセスしてLocustのweb UIを開きます。

Number of users(負荷をかけるユーザ数の最大値を設定)

Spawn rate(ユーザ数の増加レートを指定)

[start swarming] で負荷テストを実行できます。
ちなみにspawnは産卵、swarmは群れという意味があり、
Locustの世界観を感じられるUIだなーと思いました。

実行すると以下のような形で確認できます。

Failuresタブではエラーレスポンスも確認できます。

ログ
'Post "http://localhost:8080/ping": 
context deadline exceeded (Client.Timeout exceeded while awaiting headers)'

ちゃんとタイムアウトエラーが記録されていますね!
エラー率も4%なので妥当そうです。(単純に50/1050と考えた場合。。)


Locust + BoomerのQuick Startは以上です!
簡単なHTTPリクエストのテストで、workerも一つだけですが、ここまでできてしまえば無限に拡張できますね!

Locustはworkerを複数使用して分散負荷をかけることができ、kubernetes上で実行することもできるようですので、まだまだパワフルな使い方がありそうです。

最後に、実際に動かしてみてLocustに少し親しめました。BoomerもGoで簡単にテストシナリオを実装できるので、今後実用できるよういろいろ試してみたいと思います!

参考

DMM.go #4「マイクロサービスプラットフォーム向け負荷試験基盤の初期リリースを終えた話」イベントレポート
gRPC + Locust + boomerで負荷試験をしてみた