LocustをKubernetes上で構築して分散負荷テストして、Linkerdでサービスメッシュのデバッグを行う
動機
実はLocustは10ヶ月以上前に使ったことがあります。
しかし、今回はサービスメッシュをLinkerd
で構築して、マイクロサービス間のレイテンシなどを計測していこうと思いました。
Locust
概要
Locustとは
オープンソースな負荷テストツール
です。公式サイトは以下の通りです。
Locust - A modern load testing framework
特徴
- コードによって負荷テストの振る舞いを定義します
- 分散かつスケーラブルな負荷テストを提供します
- 信頼度が高く、実用的です
インストール
以下のコマンドでインストールすることができます。
python3 -m pip install locustio
macOSユーザーは以下の依存パッケージもインストールしないといけません。
brew install libev
負荷テストを構築する
taskを定義
典型的なtaskの定義方法はデコレーター@task
をつける方法ある。
from locust import Locust, TaskSet, task class MyTaskSet(TaskSet): @task def my_task(self): print("Locust instance (%r) executing my_task" % (self.locust)) class MyLocust(Locust): task_set = MyTaskSet
引数で重みを定義することができて、これが比率になる。忘れている人がいるかもしれないので言っておくが、pass
とは何もしない関数を定義するものである。
from locust import Locust, TaskSet, task class MyTaskSet(TaskSet): min_wait = 5000 max_wait = 15000 @task(3) def task1(self): pass @task(6) def task2(self): pass class MyLocust(Locust): task_set = MyTaskSet
task_setを定義
タスクの集合を定義するにはtask_set
に引数がTaskSet
のタスククラスを定義することである。
Setups, TearDowns, on_start, on_stop
Setups, TearDowns
on_start, on_stop
HTTPRequestを定義する
負荷テストではDos攻撃のようにすると思うので、HTTPリクエストを送ることになると思います。HTTPLocust
を使うと簡単に送ることができます。
Locust
を引数で渡していたのが、HTTPLocust
にすることで定義でき、self.client
にメソッドがあります。
from locust import HttpLocust, TaskSet, task class MyTaskSet(TaskSet): @task(2) def index(self): self.client.get("/") @task(1) def about(self): self.client.get("/about/") class MyLocust(HttpLocust): task_set = MyTaskSet min_wait = 5000 max_wait = 15000
もちろんHTTPメソッドはカバーしていて、以下のように取得することができます。
response = self.client.get("/about") print("Response status code:", response.status_code) print("Response content:", response.text)
実行する
WebUIから
以下のコマンドで準備することができます。
locust --host=http://example.com
実行するとWebUIから実行を確認することができます。
ここでは以下の項目を設定することになります。
- クライアントの総数
- ハッチレート(毎秒いくつクライアント追加するか)
WebUIなしで
以下のオプションをつければWebUIなしで実行することができます。
--no-web -c 1000 -r 100
ここで
-c
: クライアントの数-r
: ハッチレート
です。
Kubernetesクラスタで構築
Helmでインストール
以下のコマンドでインストールします。
helm install -n locust-jobs --set master.config.target-host=http://site.example.com stable/locust
これはdefault
namespaceにインストールされます。
Podを確認すると
$ kubectl get pods locust-job-master-84f77746d8-gjtpx 0/1 ContainerCreating 0 3s locust-job-worker-5bdd6647bf-f9fts 0/1 ContainerCreating 0 3s locust-job-worker-5bdd6647bf-ttbqx 0/1 ContainerCreating 0 3s
です。Serviceは
$ kubectl get services locust-job-master-svc NodePort 10.55.243.4 <none> 8089:31060/TCP,5557:30302/TCP,5558:30624/TCP 58s
です。
次にWebUIにアクセスをします。
$ kubectl port-forward locust-job-master-84f77746d8-gjtpx 8089
を実行して、アクセスしてください。
すると以下のような画面が出ると思います。
以下のようなコマンドを送ってください。
ここでLOCUST_URL
はlocalhost:8089
です。
curl -X POST $LOCUST_URL/swarm -d "locust_count=100&hatch_rate=10"
実際にUIで確認すると以下のようになっています。
さらに負荷をあげると以下のようになりました。
色のついたtest-1
が非常にCPUを食っていることがわかりました。
またtest-1
とtest-2
については以下のようになっていました。
特にレイテンシがtest-1
とtest-2
はよくありませんでした。
遅いものが極端に遅いので、スパイクを打っていることが考えられます。
特にtest-1
があるNodeが以下のようになっていました。
CPU使用率が以上に高いです。
なのでHorizontal Pod AutoScaler
をつけたところロードバランシングされる様子が分かります。
しかしながら、いきなり急にトラフィックを分けられるわけではなくて、徐々っという感じです。
以下のような結果になりました。
やはり負荷が高いのが原因だと考えられます。
今後
次はKubernetesのResource
の使い方を詳しく勉強しようと思います。