locustの負荷テスト環境をaws上に構築する

# 概要
システムの負荷テストを行う機会があったので、locustを使ってAWS上に負荷テストを実行できる環境を構築する手順を備忘録として残します。

### なぜAWS上に構築するのか
locust自体はローカルマシンでも実行できるのですが、単純にマシンスペックが足りず思っていたような負荷がかけれなかったためです。

ローカルでの実行時は以下のような感じ。
wait_timeやworker数など色々調整して100RPS弱。

マシンのCPUがほぼ100%利用だったので限界っぽい。

![screencapture-0-0-0-0-8089-2023-12-24-18_27_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/c8099bec-b38e-2652-8f40-a21759d543c3.png)



# 構築
locustの公式がリソースを構築するためのTerraformコードを提供してくれています。
- https://docs.locust.io/en/stable/running-cloud-integration.html
- https://github.com/locustio/locust/blob/master/examples/terraform/aws/README.md

ただし、ここでsourceとして指定されているTerraform Moduleに問題があってそのままでは利用できなかったので、source側のコードを修正して利用することにしました。

source側リポジトリ(locust)
https://github.com/marcosborges/terraform-aws-loadtest-distribuited/tree/master/examples/locust

## 基本設定
ワーカー数(ノード数)の指定をします。
今回は4を指定したので、locustのマスターノードと、4つのワーカーノードが起動します。
```variables.tf
variable "node_size" {
    description = "Size of total nodes"
    default = 4
}

variable "locust_plan_filename" {
    default = "locust/basic.py"
}
```

locustを実行するサーバーを立ち上げるサブネットを指定しましょう。
```data_subnet.tf
data "aws_subnet" "current" {
    filter {
        name   = "tag:Name"
        values = ["リソースを構築するサブネット名"]
    }
}
```

おまけ。
ssh_export_pemをtrueにしておくと、リソース作成時にsshキーが吐き出されるので、サーバーに入ることができます。
```main.tf

module "loadtest" {
    ...省略...
    
    ssh_export_pem = true
}
```

### terraform applyする
リソースの構築が完了するとダッシュボードのURLが表示されます。
```bash
dashboard_url = "http://43.207.71.14"
leader_private_ip = "10.5.0.64"
leader_public_ip = "43.207.71.14"
nodes_private_ip = [
  ...
]
nodes_public_ip = [
  ...
]
```

ダッシュボードにアクセスできません。
普通に設定をいじるだけではlocustがうまく起動しないので、解決していきます。
![スクリーンショット 2023-12-24 17.10.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/a1816c97-c6f5-c31f-02dc-37e335f6e2c7.png)

## 問題点の修正
以下のissueでも指摘されていますが、locust内部で利用するurllib3 2.0とOpenSSLのバージョンが適合しないため下記エラーが出ます。
https://github.com/locustio/locust/issues/2357

```
Traceback (most recent call last):
  File "/usr/local/bin/locust", line 5, in <module>
    from locust.main import main
  File "/usr/local/lib/python3.7/site-packages/locust/__init__.py", line 14, in <module>
    from .user.sequential_taskset import SequentialTaskSet
  File "/usr/local/lib/python3.7/site-packages/locust/user/__init__.py", line 2, in <module>
    from .users import HttpUser, User
  File "/usr/local/lib/python3.7/site-packages/locust/user/users.py", line 6, in <module>
    from urllib3 import PoolManager
  File "/usr/local/lib/python3.7/site-packages/urllib3/__init__.py", line 42, in <module>
    "urllib3 v2.0 only supports OpenSSL 1.1.1+, currently "
ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips  26 Jan 2017'. See: https://github.com/urllib3/urllib3/issues/2168
```

とりあえずの対応としてurllib3のバージョンを落として対応します。

また、locustのバージョンが`2.9.0`と古いバージョンになってるので、できるだけ新しいものに上げておきました。
(インストールされてるpythonのバージョンが`3.7`なので、`3.7`で使えるうち最新の`2.17.0`にしてます)
```diff:scripts/locust.entrypoint.leader.full.sh.tpl
- export LOCUST_VERSION="2.9.0"
+ export LOCUST_VERSION="2.17.0"
+ sudo pip3 uninstall urllib3
+ sudo pip3 install urllib3==1.26.6

sudo pip3 install locust==$LOCUST_VERSION
```
ノード側のエントリーポイントファイルも同じように変えてください。

### terraform apply
うまく起動してダッシュボードにアクセスできるようになりました。

![スクリーンショット 2023-12-24 18.10.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/a3794b12-a38d-d4b2-9e5e-b698696494fe.png)

RPSもローカルで実行したときより断然出てますね。
これはワーカー数=2、ユーザー数=300、wait_time=0で実行してますが、もっとワーカー数(ノード数)、ユーザー数を増やせばRPSを上げてくことはできそうでした。

![stg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532805/9ad03c4d-efdf-a3be-0e29-a5485b93aa02.png)


# 所感
AWS上など複数マシンで負荷テスト実行を行えば割と大きな負荷をかけることができそうですね。
構築と破壊も簡単なので、利用したいときだけ負荷テスト環境を立ち上げれば対してコストもかからなそうです。