Kekeの日記

エンジニア、読書なんでも

LocustをKubernetes上で構築して分散負荷テストして、Linkerdでサービスメッシュのデバッグを行う

f:id:bobchan1915:20180930111212p:plain

動機

実は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から実行を確認することができます。

http://127.0.0.1:8089

f:id:bobchan1915:20180930125737p:plain

ここでは以下の項目を設定することになります。

  • クライアントの総数
  • ハッチレート(毎秒いくつクライアント追加するか)

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

これはdefaultnamespaceにインストールされます。

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

を実行して、アクセスしてください。

すると以下のような画面が出ると思います。

f:id:bobchan1915:20180930182045p:plain

以下のようなコマンドを送ってください。

ここでLOCUST_URLlocalhost:8089です。

curl -X POST $LOCUST_URL/swarm -d "locust_count=100&hatch_rate=10"

実際にUIで確認すると以下のようになっています。

f:id:bobchan1915:20180930183531p:plain

さらに負荷をあげると以下のようになりました。

f:id:bobchan1915:20180930184545p:plain

色のついたtest-1が非常にCPUを食っていることがわかりました。

またtest-1test-2については以下のようになっていました。

f:id:bobchan1915:20180930184654p:plain

特にレイテンシがtest-1test-2はよくありませんでした。

f:id:bobchan1915:20180930184741p:plain

遅いものが極端に遅いので、スパイクを打っていることが考えられます。

特にtest-1があるNodeが以下のようになっていました。

f:id:bobchan1915:20181001142742p:plain

CPU使用率が以上に高いです。

なのでHorizontal Pod AutoScalerをつけたところロードバランシングされる様子が分かります。

f:id:bobchan1915:20181001145007g:plain

しかしながら、いきなり急にトラフィックを分けられるわけではなくて、徐々っという感じです。

以下のような結果になりました。

f:id:bobchan1915:20181001145621p:plain

f:id:bobchan1915:20181001145628p:plain

やはり負荷が高いのが原因だと考えられます。

今後

次はKubernetesのResourceの使い方を詳しく勉強しようと思います。