locustによる負荷試験とアラーム
今はautoscaleの事は考えない。メンテナンス用のEC2を1つ用意しておく、ってか用意してあるか既に。このEC2を使って負荷試験するといいんじゃないかな?
前提条件
ECSでロードバランサ(ALB)経由にてtaskが1つだけ動いている。先述の通り、オートスケールはしない。このタスクは
arm64
vcpu: 0.25
mem: 0.5
というほとんど最小構成みたいな感じで動いている。こいつの性能でどこまで行けるか確認してみよう。なお、ファイルはefsに置いてあり、またrdsにデーターを保存し、セッションもそこに入っている。rdsはdb.t4g.microとかだったとおも。
locust用のセキュリティーグループを作る
locustってのはport8089を使ってwebインタフェースを提供するので、これを開放する。
で、このホストにsshする
$ sudo apt update
Get:1 file:/etc/apt/mirrors/debian.list Mirrorlist [38 B]
Get:4 file:/etc/apt/mirrors/debian-security.list Mirrorlist [47 B]
Hit:2 https://cdn-aws.deb.debian.org/debian bookworm InRelease
Get:3 https://cdn-aws.deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
Get:5 https://cdn-aws.deb.debian.org/debian bookworm-backports InRelease [56.5 kB]
Get:6 https://cdn-aws.deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Get:7 https://cdn-aws.deb.debian.org/debian bookworm-backports/main Sources.diff/Index [63.3 kB]
Get:8 https://cdn-aws.deb.debian.org/debian bookworm-backports/main arm64 Packages.diff/Index [63.3 kB]
Get:9 https://cdn-aws.deb.debian.org/debian bookworm-backports/main Translation-en.diff/Index [57.7 kB]
Get:13 https://cdn-aws.deb.debian.org/debian bookworm-backports/main Sources T-2024-02-06-1417.20-F-2024-02-05-0834.18.pdiff [8417 B]
Get:13 https://cdn-aws.deb.debian.org/debian bookworm-backports/main Sources T-2024-02-06-1417.20-F-2024-02-05-0834.18.pdiff [8417 B]
Get:14 https://cdn-aws.deb.debian.org/debian bookworm-backports/main arm64 Packages T-2024-02-06-1417.20-F-2024-02-05-1410.56.pdiff [25.5 kB]
Get:15 https://cdn-aws.deb.debian.org/debian bookworm-backports/main Translation-en T-2024-02-06-1417.20-F-2024-02-06-1417.20.pdiff [4429 B]
Get:14 https://cdn-aws.deb.debian.org/debian bookworm-backports/main arm64 Packages T-2024-02-06-1417.20-F-2024-02-05-1410.56.pdiff [25.5 kB]
Get:15 https://cdn-aws.deb.debian.org/debian bookworm-backports/main Translation-en T-2024-02-06-1417.20-F-2024-02-06-1417.20.pdiff [4429 B]
Get:10 https://cdn-aws.deb.debian.org/debian-security bookworm-security/main Sources [79.4 kB]
Get:11 https://cdn-aws.deb.debian.org/debian-security bookworm-security/main arm64 Packages [134 kB]
Get:12 https://cdn-aws.deb.debian.org/debian-security bookworm-security/main Translation-en [81.4 kB]
Fetched 674 kB in 2s (388 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
bookwormなdebianでした。
locustを入れる
このバージョンのdebianにはパッケージとして付いてきてるのでそれを使うのがいいだろう。そうでなければpipとか使うのかな?よくわかんえわ、pythonの作法は
$ sudo apt install python3-locust
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
fonts-font-awesome fonts-lato javascript-common libc-ares2 libev4 libjs-jquery libjs-sphinxdoc
libjs-underscore libnorm1 libpgm-5.3-0 libzmq5 python3-asgiref python3-brotli python3-click
python3-configargparse python3-dotenv python3-flask python3-flask-basicauth python3-flask-cors
python3-gevent python3-geventhttpclient python3-greenlet python3-itsdangerous python3-msgpack
python3-openssl python3-psutil python3-py python3-pyinotify python3-roundrobin
python3-simplejson python3-typing-extensions python3-werkzeug python3-zmq python3-zope.event
python3-zope.interface sphinx-rtd-theme-common
Suggested packages:
apache2 | lighttpd | httpd python-flask-doc python-gevent-doc python-greenlet-dev
python-greenlet-doc python-openssl-doc python3-openssl-dbg python-psutil-doc subversion
python3-pytest python-pyinotify-doc ipython3 python-werkzeug-doc python3-lxml python3-watchdog
The following NEW packages will be installed:
fonts-font-awesome fonts-lato javascript-common libc-ares2 libev4 libjs-jquery libjs-sphinxdoc
libjs-underscore libnorm1 libpgm-5.3-0 libzmq5 python3-asgiref python3-brotli python3-click
python3-configargparse python3-dotenv python3-flask python3-flask-basicauth python3-flask-cors
python3-gevent python3-geventhttpclient python3-greenlet python3-itsdangerous python3-locust
python3-msgpack python3-openssl python3-psutil python3-py python3-pyinotify python3-roundrobin
python3-simplejson python3-typing-extensions python3-werkzeug python3-zmq python3-zope.event
python3-zope.interface sphinx-rtd-theme-common
0 upgraded, 37 newly installed, 0 to remove and 0 not upgraded.
Need to get 8940 kB of archives.
After this operation, 33.3 MB of additional disk space will be used.
Do you want to continue? [Y/n]
って感じなので入れる
クリーンナップスクリプトを作る
DBだのファイルだのをバリバリとアップロードしていくので汚れちゃうでしょう。
sudo mount -t nfs4 fs-0d43cd7e72cc13d9b.efs.ap-northeast-1.amazonaws.com:/ /mnt
sudo rm -rf /mnt/data/*
sudo umount /mnt
echo "drop table uploaded_files" | mysql -uadmin -ppassword -huploader-demo.cmxstlofflyf.ap-northeast-1.rds.amazonaws.com uploader_demo
echo "drop table session_data" | mysql -uadmin -ppassword -huploader-demo.cmxstlofflyf.ap-northeast-1.rds.amazonaws.com uploader_demo
mysql -uadmin -ppassword -huploader-demo.cmxstlofflyf.ap-northeast-1.rds.amazonaws.com uploader_demo < /home/admin/old-style-php5-uploader/init/schema.sql
mysql -uadmin -ppassword -huploader-demo.cmxstlofflyf.ap-northeast-1.rds.amazonaws.com uploader_demo < /home/admin/session_data.sql
なんかやんちゃすぎる気もするけど、とにかく初期状態に戻せれば何でもいい。
テストを実行していく
locustfile.pyの記述
これは完全なpythonプログラムである
from locust import HttpUser, task
class WebsiteUser(HttpUser):
@task
def index(self):
self.client.get("/")
これは対象プログラムの / にアタック(負荷)をかけまくるという事になるな。
ただ、今回
index.phpを /GET
index.php?action=save にfileをアップロード
の2点をチェックしたい。とくにPOSTが重要なので、それも含めたシナリオを記載する
locustfile.py
from locust import HttpUser, task, between
class FileUploadUser(HttpUser):
wait_time = between(1, 5) # ユーザーのアクション間の待機時間を1〜5秒の間でランダムに設定
@task
def upload_flow(self):
# ステップ1: index.phpのフォームをGETリクエストで取得
self.client.get("/index.php")
# ステップ2: ファイルをアップロードするPOSTリクエストを送信
files = {'file': ('test.jpg', open('test.jpg', 'rb'))}
self.client.post("/index.php?action=save", files=files)
# ステップ3: リダイレクト後のページをGETリクエストで取得(必要に応じて)
# self.client.get("/path/to/redirect/page")
準備が整ったので起動しよう
$ locust -f locustfile.py
8089ポートにアクセスするとこのような感じになる。とりあえず上も下も1 1にし、hostを対象のhostにセットして実行してみよう
このようにガンガンファイルがアップロードされ続ける。適当なところでstopした
このように44ファイルアップロードされたのが結果として理解できる。ではその課程を読み解いていこう
最上段
なんかスクショが切れちゃったけどRPS0.6% FAILURES 0%と書いてある。
RPSとはRequests per secondsであるが、まあここでは失敗したリクエストが無い点に注意する。
とくにリアルタイムで見ていくと最初の方は90%タイルも99%タイルも同じ秒数なんだが(そら当然ともいえるが)、段々パフォーマンスの劣化が出てくると99%タイルから落ちはじめていく。ただし変なところで詰まると99%タイルだけやたら秒数がかかるようになる事もあるから、いろいろベンチを取って経験値を積んでいくしかないだろう。
cloudwatchアラームを設定してみる
こんな感じでテストした形跡がある
期間を5分にするとさすがに反応が遅いため1分にする。ただ30秒とかにすると金がかかるぞーって警告してくる
ここでは20%を閾値にしている。まあ、より大きいでも以上でも、ここはそんな変わらないだろう。異常検出はAIみたいなもんらしい、使ったことないがコストがかかるぞい。
最後にいろいろアクションを設定できる。とりあえず何もしない。
さて、これでまた負荷テストと行ってみよう
負荷テストと監視
今回は通知を入れていないのでアラームをぼんやり見ておく
うん、これねえ、2回試行しても越えませんでしたw
じゃあ3にするかと
3ユーザーでついにアラームに到達し、警告が出ておりますね。とはいえ20%つのはまだ余裕がありそうでなさそうでみたいな感じですが。もうちょい回してみます
どうやら30%ちょいくらいのところで耐えはじめたみたいですね。ここで負荷試験を終える
でまあstatsなんですが
この変がいずれも1秒以内で処理できてるので「まあ何とかなってるよ」と判断できそうだ。試験を止めると
ちゃんとアラームが正常になる。
本当にダメな場合を見てみよう
たとえば20ユーザーとかが来ちゃった場合
この辺でスパイクしているのがわかる。3〜4秒応答にかかるようになった。まあしかしおせえんだけどギリ何とかなるっちゃなんとかなるのかもだが、まあ遅いとは思いますな。こういう時はタスクの数をいくつか増やして対応する。大体、1タスクで5ユーザーくらい何とかなってた雰囲気があるから4タスク起動してみよう。
じゃまあ、やってみましょう。
4タスクで捌く
まあアラーミーなんだけど、50%くらいで耐えているようだ。
run#4とrun#5の違いはrun#4は1タスク、#5は4タスクでの分散ですから、これはもう一目瞭然っすね