負荷試験ツールLocustをサクッと試してみた（CLI実行）

# はじめに
* 負荷試験ツール[Locust](https://docs.locust.io/en/stable/index.html)を軽く試して見た時のメモです。

# Locustの特徴
* テストシナリオをPythonで記述できる
* 分散実行できる（スケールさせることができる）
* WebベースのUIが備わっている
* 様々な種類のテストに対応することができる（Webサイト、Webサービス以外にも様々なシステムやプロトコルに対応することができる）
* 拡張しやすい（Locust本体はスモールでフレキシブル）

# 前提
* ログイン認証→検索処理実行する簡単なAPIを、LocustのCLIでテストしたときの手順です。

* 手動で実行する場合のコマンドは下記です。

```bash
$ curl -X POST -H "Content-Type: application/json" -d '{"userId":"user001", "password": "P@ssw0rd!"}' http://target-system:80/login
$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <token>" -d '{"itemId": "aaaaa"}' http://target-system:80/search
```

* 下記の条件でテストをしています。
    * 2ユーザ（ログインは最初の一回、のべ2回のみ）
    * 負荷試験時間は60s

# 手順
## locustインストール

```bash
$ pip3 install locust
$ locust -V
# -> locust 1.4.1
```

## 設定ファイル準備

```python:locustfile.py
from locust import HttpUser, TaskSet, task, between, constant

class UserBehavior(TaskSet):
    token = ""

    def on_start(self):
        # login
        response = self.client.post(
            url="/login",
            headers={
                'content-type': 'application/json'
            },
            json={
                "userId": "user001",
                "password": "P@ssw0rd!"
            }
        )
        self.token = (response.json()["token"])

    # task(XX): 実行順番
    @task(1)
    def search(self):
        authorization = "Bearer " + self.token
        response = self.client.post(
            url = "/search",
            headers = {
                'Authorization': authorization,
                'content-type': 'application/json'
            },
            json={
                "itemId": "aaaaa",
            }
        )

class WebsiteUser(HttpUser):
    # ex. {my_task: 3, another_task: 1}: 3対1の割合でランダムで実行する
    tasks = {UserBehavior:1}
    # wait_time: タスク間の時間
    wait_time = constant(5)
```

## Configファイル準備

```bash:locust.conf
locustfile = locustfile.py
headless = true
host = http://target-system:80
users = 2
# spawn-rate: 1秒あたりに増加する秒間ユーザ数
spawn-rate = 1
run-time = 60s
loglevel = DEBUG
```

## CLI実行

```bash
# 負荷試験実行
$ locust --config=locust.conf

# -> 出力結果例
 Name                                                          # reqs      # fails  |     Avg     Min     Max  Median  |   req/s failures/s
--------------------------------------------------------------------------------------------------------------------------------------------
 POST /login                                                        2     0(0.00%)  |     329     315     342     320  |    0.07    0.00
 POST /search                                                      12     0(0.00%)  |      64      46      87      58  |    0.45    0.00
--------------------------------------------------------------------------------------------------------------------------------------------
 Aggregated                                                        14     0(0.00%)  |     102      46     342      58  |    0.52    0.00

Response time percentiles (approximated)
 Type     Name                                                              50%    66%    75%    80%    90%    95%    98%    99%  99.9% 99.99%   100% # reqs
--------|------------------------------------------------------------|---------|------|------|------|------|------|------|------|------|------|------|------|
 POST     /login                                                            340    340    340    340    340    340    340    340    340    340    340      2
 POST     /search                                                            58     72     79     79     79     87     87     87     87     87     87     12
--------|------------------------------------------------------------|---------|------|------|------|------|------|------|------|------|------|------|------|
 None     Aggregated                                                         72     79     79     87    320    340    340    340    340    340    340     14
```

# 感想
* pip一発でサクッとインストールできるし、使い方もシンプルだし、Pythonなのでどうとでもなる感があるし、良さそうな感じがします。