負荷テストツールLocustのインストールと実行
先日、負荷テストの話題になって聞き慣れないツールの名前が出たので調べてみました。
負荷テストのツールと言えば、簡易的なもので「Apache Bench」、もう少し凝ったことをやろうとして「JMeter」というイメージでした。
今回は、Python のコードでシナリオが記述できる「Locust」のインストール手順と実行方法を紹介します。
イナゴ?バッタ?の大群が襲ってくる負荷テストツール
「負荷試験にイナゴを使ってみたいんだよね」
そんな一言がこの話題の発端でした。
知らない人は「イナゴ」てググっていいのか、「175」でググるべきなのか迷うところですが、後者はもしかすると 175R を知ってる世代だけでしょうか。
要は「Locust」のことなのですが、「ローカスト」や「ルーカスト」などと呼んでいる人がいるようです。
(まあ、純粋に英語ですよね)
Locustの特徴
冒頭にもチラっと書きましたが、以下の特徴を持った負荷試験ツールです。
・シナリオがPythonで書ける
・分散テストができる
・WebのUIから負荷試験ができる
そういえば、数年前に Web の UI を持った負荷試験ツールを触ったことがあるような記憶が蘇ってきました。
もしかすると見たことのある UI かもしれないと早く画面が見たくなりますが、まずは試してみます。
Locustのインストール
Python のツールなので、pip コマンドでインストールをします。
pipコマンドの確認
pip コマンド自体は Lets’ Encrypt を同じサーバで利用しているので既に入っていました。
$ pip -V
pip 9.0.3 from /usr/lib/python2.7/dist-packages (python 2.7)
インストール実行
早速、locust のインストールです。
$ pip install locustio
You are using pip version 9.0.3, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
最後に警告が出ましたが、pip のバージョンってこんなに差異があるの?
アップグレードして Let’s Encrypt の証明書更新ができなくなるのが嫌なので別のサーバで試みます。
別サーバでpipのアップグレード
無理にアップグレードする必要はないかもしれませんが、気になるので pip のアップグレードをしてから locust のインストールをすることにします。
$ pip install --upgrade pip
Installing collected packages: pip
Found existing installation: pip 9.0.3
Uninstalling pip-9.0.3:
Successfully uninstalled pip-9.0.3
Successfully installed pip-18.0
アップグレードが完了してバージョンが 18.0 になりました。
$ pip -V
pip 18.0 from /usr/lib/python2.7/dist-packages/pip (python 2.7)
再度Locustのインストール実行
そのまま pip をアップグレードしたサーバで locustio をインストールします。
$ pip install locustio
cloud-init 0.7.6 requires argparse, which is not installed.
cloud-init 0.7.6 requires cheetah, which is not installed.
cloud-init 0.7.6 requires oauth, which is not installed.
cloud-init 0.7.6 requires PrettyTable, which is not installed.
cloud-init 0.7.6 requires pyserial, which is not installed.
Cannot uninstall 'chardet'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
警告なしでスムーズにいくかなと期待しましたが、今度は 6 個のエラーが出力されましたorz
この時点で、無理にアップグレードするんじゃなかったと少々の後悔・・・。
仕方ないので足りないパッケージのインストールをして、chardet のエラーを解決してから再度 locustio のインストールをします。
まずは、パッケージのインストールから。以下の 5 つのパッケージをインストールします。
$ pip install argparse cheetah oauth PrettyTable pyserial
最後にエラーの内容通り chardet を手動で削除します。
$ rm -f /usr/lib/python2.7/dist-packages/chardet-2.0.1.egg-info
$ rm -rf /usr/lib/python2.7/dist-packages/chardet
今度はエラーなくインストール完了です。
$ pip install locustio
バージョンを確認すると 0.8.1 となっています。まだ 1 を超えないのか・・・。
$ locust -V
Locust 0.8.1
Locustの実行
早速、使ってみたいと思いますが、Locust の Web UI の画面は8089 番ポートで待ち受けます。
AWS のセキィリティグループを触ってポートを開けるのが嫌だったので、nginx でリバースプロキシすることにしました。
ざっくり、こんな感じで設定ファイルを作って適当なドメインを振っておきます。
(何かのサブドメインとかでも)
気休めで Basic 認証でもしておきます。
server {
server_name locust.example.org;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Authorization "";
location / {
proxy_pass http://127.0.0.1:8089;
}
}
Locust の設定ファイルは「locustfile.py」というファイル名にしておくとデフォルトの設定ファイルとして読み込んでくれます。
設定内容は、トップページとリンク先のページに順番にアクセスする単純な画面遷移とします。
$ vi locustfile.py
from __future__ import absolute_import
from __future__ import unicode_literals
from locust import HttpLocust, TaskSet, task
class TaskSet1(TaskSet):
@task
def index(self):
self.client.get("/")
@task
def page(self):
self.client.get("/hoge/fuga")
class Wp(HttpLocust):
task_set = TaskSet1
min_wait = 1000
max_wait = 1000
これで Locust を起動して待ち受けてみます。
$ locust -H https://example.com
簡単に上記コマンドを説明すると、-H オプションで負荷を掛けたい相手先のホストを指定しています。
詳しくはヘルプを見てください。locustfile.py 以外の設定ファイルを使いたい場合は -f で指定します。
$ locust -h
Usage: locust [options] [LocustClass [LocustClass2 ... ]]
Options:
-h, --help show this help message and exit
-H HOST, --host=HOST Host to load test in the following format:
http://10.21.32.33
--web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all
interfaces)
-P PORT, --port=PORT, --web-port=PORT
Port on which to run web host
-f LOCUSTFILE, --locustfile=LOCUSTFILE
Python module file to import, e.g. '../other.py'.
Default: locustfile
Locustの画面にアクセスしてテスト開始
では、nginx で設定した locust.example.org にアクセスしてみます。
問題がなければ、以下の設定が表示されます。
やはりこのツール、何年か前に Python 好きなエンジニアの人が使っていて紹介されたものでした。
このシンプルな画面は見覚えがあります。
ちなみに、設定項目は以下の通りです。
Number of users to simulate:クライアントの数
Hatch rate:クライアントの生成速度
今回はシンプルに 1 ユーザから始め、1 秒ごとに 1 ユーザずつ増加させていくことにしました。
これだと平均のレスポンス時間も短いですね。しかも、サイト側は nginx のキャッシュ利かせていますからね。
Max(ms)が 115 になっているアクセスはキャッシュが効いていない初回アクセスだったのかも。
設定を変更して負荷を上げる
画面上部の赤いストップボタンで停止し、ステータス付近の「New test」からユーザ数や増加数を変更してテストが開始できます。
今度は、5 ユーザから始まり毎秒 5 ユーザ増やしてみます。
やはりワードプレス相手でもキャッシュが効いていると速いですね。
この程度なら余裕で捌けます。
そして「100 / 100」で設定して秒間 100 にしても全く問題ありません。
キャッシュしちゃってるだけに、静的なページが返るだけですからね。
でもワードプレスの負荷軽減にページキャッシュは大きく貢献していることがわかります。
「500 / 500」の設定から、ある程度アクセスを捌けてはいるものの、徐々にロードアベレージが増加してきました。
まとめ
Locust をサーバにセットアップして、簡単な負荷を特定のサイトにかけてみました。
実は今回、同じサーバのサイトに対して行ったので、実際はもう少し状況は変わってくるハズです。
本来ならリモートからやらないとあまり意味もないですしね。
また、シナリオが Python で書けるので、もっと凝ったシナリオも作れそうです。