分散負荷試験という選択肢

この記事は[ZOZOテクノロジーズ #4 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/zozo_tech4)の16日目の記事です。
昨日は [@matsumana07384](https://qiita.com/matsumana07384)さんの [HTMLのInput要素のinputmodeのスマートフォンのキーボードがどのように表示されるを整理してみた](https://qiita.com/matsumana07384/items/4b6d70bbf2a819228596) でした。

##はじめに

はじめまして。ZOZOテクノロジーズでSRE部に所属している[@akitok](https://twitter.com/akitok_)です。

皆さん負荷試験していますか？
システムの信頼性・安定性を担保するために、非常に重要なフェーズといえる負荷試験。
システムへのアクセスが増大し、目標スループットが高くなっていくにあたり、
そもそも目標スループットを再現した負荷をかけること自体が難しくなってきます。
この記事では、その難しさ・辛さに焦点をあて、分散負荷試験という選択肢を紹介します。

##負荷試験の辛さ

負荷試験をしていて、こんな経験はありませんか？

- 一定程度高い負荷をかけ始めると、むしろリクエストを投げているサーバ（負荷実行サーバ）がソケット枯渇、空きポート不足などで死ぬ
- 色々チューニング（各ツールの設定や、OSレベルのチューニング）を頑張っても、リクエスト量が増えていくと、やはり負荷実行サーバが死ぬ
- カリカリにチューニングした負荷実行サーバを複数台準備し、並列に負荷実行させるも、負荷実行サーバが数台死んだので、同じようにチューニングしたサーバを増設してやり直し
- 無事に並列実行が完了したが、X台分のテスト結果をマージするのが辛い
- 苦労してマージしてみたら、エラーを発見し、やり直し

もし、このような経験がある方は、身に沁みて分かるのではないかと思いますが、
そうなんです。想定するスループットが高くなれば高くなるほど、そもそも負荷をかけきるまでで一苦労なんです。

## 分散負荷試験という選択肢
このような負荷試験の辛さを解消するために、各負荷試験ツールでは、負荷試験サーバのスケールアウトや分散並列実行など、
様々に分散負荷実行の手段を用意・サポートしています。
ここでは、私が負荷試験を検討するにあたり、候補として見たものを紹介します。

### Gatling
[Gatling](https://gatling.io/)は、Scalaで作成された負荷試験ツールです。
以下のような特徴があります。

- Scalaでシナリオを記述する
- HTMLで出力されたレポートを自動生成
- ブラウザ操作を記録してシナリオを生成してくれるRecorder機能

分散実行に関しては、以下のような方法があります。

#### GatlingFrontLine(Enterprise License)での分散実行
https://gatling.io/docs/current/cookbook/scaling_out/#scaling-out-easily-with-gatling-frontline

- Enterprise Licenseである[GatlingFrontLine](https://gatling.io/gatling-frontline/)を使えば、クラスタモードでの分散負荷試験、レポート作成ができるようです。
- AWS、GCP、Azureへデプロイすることもサポートされているようなので、検討してみても良いかもしれません。


#### Gatling(OSS)レポート集約
https://gatling.io/docs/current/cookbook/scaling_out/#scaling-out-with-gatling-open-source

- OSSとしてのGatlingは、クラスターモードでの分散負荷実行をすることは出来ませんが、個々に独立して実行した結果をマージして、レポートを生成することができます。
- そのため、複数台のGatlingサーバを準備し、設定を合わせ、tmuxなどを活用し、並列で実行させた結果をマージすることで分散負荷試験が可能です。
- ただ、この複数台のGatlingサーバの準備、設定合わせが、なかなかに辛いです。ただただ辛いです。

#### aws-gatling-tools
[aws-gatling-tools](https://github.com/j5ik2o/aws-gatling-tools
)は、Gatlingをコンテナ化し、Fargateとして稼働させることで、動的な分散実行を実現し、Gatlingの設定合わせ、シナリオ同期、結果集約などの辛さから解放してくれるツールです。
システムインフラにAWSを活用しているユーザにとっては、有効な選択肢と言えるのではないでしょうか。
このツールの作成者であるかとじゅんさんの[ブログ記事](https://note.com/j5ik2o/n/n530ca245a18c)がわかりやすいです。
以下のような特徴があります。

- Fargate on ECSの環境を構築(Terraformで実現)し、Gatlingを並列実行
- Gatlingの並列数は、負荷試験実行用シェルスクリプトに環境変数で指定することで、チューニング可能。
- 並列実行した結果レポートは集約され、Amazon S3バケットに自動で送信される。
- 負荷試験の開始や終了、レポート作成や終了などの実行状況、S3バケットにpushされたレポートURLなどをSlackやChatworkに通知できる。



### Locust
[Locust](https://locust.io/)は、Pythonで作成された負荷試験ツールです。
以下のような特徴があります。

- Pythonでシナリオを記述する
- Web UIからシナリオ実行や、実行状況の確認などが可能
- 分散負荷が可能


#### locust-distributed
https://docs.locust.io/en/stable/running-locust-distributed.html
Locustは、以下2つの要素からなる構成で、分散負荷を実現します。

- Masterノード ... テストタスクの実行管理や、Web UIを提供する
- Workerノード ... Workerノード同士で並列に協調しながら負荷をかける

なお、0.14.6以前は、Master-Slaveという名称が取られており、[1.0からMaster-Workerという名称に変わった](https://github.com/locustio/locust/blob/5ea0342c7dd3f8ab9ebe09dd8853a2947fba29c2/docs/changelog.rst#other-breaking-changes)ようです。
古い記事では、Slaveという表記が出てくると思いますが、Workerと同じものを指していることに注意してください。

また、1.0以降は破壊的な変更があったようですので、1.0以降を利用する際は、
参照する記事やドキュメントなどに注意頂いたほうが良いと思います。

#### Locust on GKE
Google Cloud Platformでは、[Google Kubernetes Engine(GKE)を使用した負荷分散テスト](https://cloud.google.com/solutions/distributed-load-testing-using-gke)をソリューションとして提供しています。
このソリューションではLocustが使われているので、Locustユーザ、GCP、GKEユーザにとっては非常に選びやすい選択肢かと思います。

### Vegeta
[Vegeta](https://github.com/tsenart/vegeta)は、Goで作成された負荷試験ツールです。
GitHubのREADME.mdにある画像がまさに[それ](https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067)ですね。
以下のような特徴があります。

- Goでシナリオを記述できる。
- レポートはテキスト、json、 ヒストグラムやそのプロットなどの形式を選択できる
- ターミナルにiTermを使っている場合、[jaggr](https://github.com/rs/jaggr)と[jplot](https://github.com/rs/jplot)と併用し、ターミナル上で[リアルタイムにスループットやレイテンシの状況が監視できる](https://github.com/tsenart/vegeta#usage-real-time-analysis)
- 分散負荷が可能

#### Distributed attacks
Vegetaは、[Distributed attacks](https://github.com/tsenart/vegeta#usage-distributed-attacks)という機能で、分散負荷をかけることが出来ます。
命名に、ビッグバンアタックみを感じて良いですね。
分散実行した結果を集約して、レポート作成もしてくれるようです。

### Distributed Load Testing on AWS
https://aws.amazon.com/jp/solutions/implementations/distributed-load-testing-on-aws/

- AWSの分散負荷テストソリューションです。[クラスメソッドさんの記事](https://dev.classmethod.jp/articles/distributed-load-testing-on-aws/)が詳しいです。
- 2020年12月現在は、JMeterシナリオ、もしくはUIからのシナリオ設定、いずれかの方法でシナリオ作成・実行が可能です。
- 既にAWSを使用し、かつ既にJMeterでシナリオを作っている方にとっては、非常に選びやすい選択肢かと思います。
- 将来的に、GatlingやLocustなどのシナリオもサポートしてもらえると嬉しい…


### 最後に
サービスレベル目標達成のため、負荷試験というフェーズはSREにとって非常に関心の高いフェーズです。
さらに、目標スループットが高くなればなるほど、負荷をかけること自体が辛くなってきます。
負荷試験は、なかなか正解に辿り着けない、我慢と根性が必要なタスクだと思います。
そういった悩みを少しでも減らすため、分散負荷試験という選択肢をいくつか紹介してみました。
各ツールは日々進化していますし、他にも様々なツールが登場してきています。ぜひ試してみてください！