注意
この記事は古く、v1.0以降は記載した実装では動作しません
別の方がv1.0での実装を記事にされていますので、そちらを参照してください
https://qiita.com/sekikatsu/items/992e82671aa505c5a652
Locustって何よ
- 負荷試験ツール
- 一度に大量のリクエストを発生させることができる
- Python
- 簡単に負荷試験の処理を定義できる
環境構築
公式で配布しているDockerImageを使ってdocker-compose.yamlを定義する
筆者の環境はMac OS Catalina(10.15.1)
ローカル環境で実行した
version: "3.4"
x-common: &common
image: locustio/locust
environment: &common-env
TARGET_URL: http://example.com
LOCUSTFILE_PATH: /tests/basic.py
volumes:
- tests/:/tests
services:
locust-master:
<<: *common
ports:
- 8089:8089
environment:
<<: *common-env
LOCUST_MODE: master
locust-slave:
<<: *common
environment:
<<: *common-env
LOCUST_MODE: slave
LOCUST_MASTER_HOST: locust-master
軽く解説。
master: UI用のWebサーバを立てる。slaveのコントロールもします。
slave: 負荷のシナリオを実行する。大きな負荷をかけたい場合は下記のようなslaveを増やす。数値で指定したような負荷がかからない場合はslaveを増やすことで対応するとよいです。
docker-compose.yaml中の locust-slave
を locust-slave1
としてリネームしてコピペすれば増えます。
TARGET_URL: 負荷をかける対象のBase URL
LOCUSTFILE_PATH: LocustFileが存在するPath.docker上でのPATHなので注意
ユースケース
- とあるアプリで、サービス開始時の瞬間的な負荷を計測したい
- APIは以下
GET /initalize: 初期化時のマスタデータ取得用
GET /item_list: 初期画面表示時のリスト表示用
POST /add_item: リストに項目を追加する用
実装
同じ階層にbasic.pyを定義
from locust import HttpLocust, TaskSequence, seq_task, between
from locust.clients import HttpSession
def initialize(l):
l.client.get("/initalize")
def item_list(l):
l.client.get("/item_list")
def add_item(l):
l.client.post("/add_item", {"item_name":"あああ"})
class ScenarioTask(TaskSequence):
# ()内の数値=実行順番
@seq_task(1)
def initialize(self):
initialize(self)
@seq_task(2)
def item_list(self):
item_list(self)
@seq_task(2)
def add_item(self):
add_item(self)
class WebsiteUser(HttpLocust):
task_set = ScenarioTask
# タスク間の時間。1~3秒でランダム秒数で実施する
wait_time = between(1.0, 3.0)
フォルダ構成
performance-test-cli
├docke-compose.yaml
└tests
└ basic.py
いざ実行
docker-compose.yamlのある階層で
docker-compose up -d
ブラウザで localhost:8089
を叩くと、以下のUIが表示されます。
以下2数値を指定して実行。
- Number of users to simulate: 最終的に到達するユーザ数(=クライアント数)
- Hatch rate: 1秒あたりに増加する秒間ユーザ数
この記事では
1ユーザあたり1秒に1回リクエストを投げるようにして、ユーザ数=秒間リクエスト数となるように調整します。
上記のStart押せば開始。
UIについて説明
- Chats タブ: どのくらいの秒間リクエストでているのか等をグラフで見れます
- Failures: リクエスト失敗した場合は簡単な例外内容含めて出してくれます
- Exceptions: 例外のStackTrace
- Download Data: CSVとして結果のデータをダウンロードできます。
- Slaves: LocustのSlaveの状態を見れます。
注意点
tests
直下に __pycache__
が出来上がる。
コンパイルしたものが格納されているようなので、実行前に消してやったほうが良いようだ。
よくある使い方
Header付けて送りたい/request bodyつけたい
def initialize(l):
l.client.get(url="/initalize",data={"item": 1},headers={"auth": "xxxxx"})
リクエストボディをjsonとして投げたい
以下のようにjsonとしてフォーマット
def add_item(l):
l.client.post(
url="/add_item",
headers={'content-type': 'application/json'},
json={"item_name":"あああ"}
)
wait_timeを1秒固定にしたい(1ユーザあたり1秒に1回リクエストを投げるようにして、ユーザ数=秒間リクエスト数となるように調整したい)
wait_time constant(1)
1つのシナリオで複数のホストへ負荷をかけたい
http://
などとして、個別にフルパスを記載すればOK
l.client.post("http://example.com/add_item", {"item_name":"あああ"})
実行順は保証されなくていいから特定のリクエストだけ多く叩いてほしい
@task(x)
の形式で記載する。
xは重み。数値が大きいほど実行頻度が高くなる
import task
...
@task(2)
def initialize(self):
initialize(self)
@task(1)
def item_list(self):
item_listz(self)
@task(3)
def add_item(self):
add_item(self)
WebUIなんて使えねえ
pythonがインストールされている環境で以下を実行
locust -f my_locustfile.py --master
※docker-composeであれば、以下条件commandに記載すればよいはず。。(試していない)
- alpineなどの別のimageにpython/locustをインストール
- 今回とは別形式のdocker-compose.yamlを作成し、commandに上記コマンドを記載
また別の記事として書こうと思います。
参考。日本語訳ないのね。
https://docs.locust.io/en/stable/running-locust-distributed.html