LoginSignup
6
2

More than 1 year has passed since last update.

GKE上に秒間1万リクエスト以上を生成できる負荷生成環境を作成する(Locust)

Last updated at Posted at 2021-11-03

はじめに

サービスのパフォーマンスチェックをするために、1万リクエスト/秒以上の負荷を瞬間的(スラムテスト)や持続的(ドリップテスト)に生成する必要が出てきました。TerraformでGoogle Kubernetes Engine(GKE)クラスタをワンコマンドで展開、負荷環境(Locust)のクラスターを作成するツールを作成しました。

https://github.com/studio-design/distributed-load-testing-using-kubernetes-locust

環境

  • Google Kubernetes Engine
  • Google Cloud SDK 361.0.0
  • Terraform 1.0.5
  • Locust Cluster (Helm)

環境構築

Terraformファイルの構成は以下です。この記事を参考にさせていただきました。

技術とかボドゲとかそんな話をしたい
正解が未だに見つからないTerraformのディレクトリ構成を考えてみた

├── projects
│   └── studio-loadtesting
│       ├── 0-build-cluster
│       ├── 1-build-monitoring
│       │   └── values
│       └── 2-deploy-locust
│           └── values
└── usecases
    └── gke_cluster
  • GKE環境の構築
  • Locust Cluster(Helm)の展開
  • 負荷スクリプトの更新(ConfigMap)

Makefileを利用して操作できるようにします。

負荷をかけるターゲットのサーバーを立てる

GCP公式のLocustサーバーテストにある、サンプル アプリケーションのデプロイでターゲットのサーバーを建てました。

Makefileの作成

以下を参考にして、Makefile.exampleからMakefileを作成します。

説明
PROJECT_ID GCPプロジェクトID
CLUSTER_NAME クラスタの基本名。クラスタの削除には時間がかかるため、このツールではベースとなるクラスタ名の最後にランダムなテキストを追加しています。
REGION GCPのRegion 
ZONE GCPのゾーン名
MACHINE_TYPE ローディングマシンのマシンタイプ。詳細はマシンタイプを参照してください
CREDENTIALS サービスアカウントのJSONファイルへのフルパスです。(相対パスは不可)
SERVICE_ACCOUNT_EMAIL サービスアカウントのEメール。例:[ユーザー名]@[プロジェクト名].iam.gserviceaccount.com
TARGET_HOST 負荷を掛ける対象ホストのURLです。

TARGET_HOSTはご自身で管理されているサーバーを指定してください。それ以外のサーバーは指定しないようにしてください。

環境の展開

まずdeployフォルダに移動します。

make help

と打つと利用できるコマンドのヘルプが表示されます。

terraformの初期化

make init_all

terraform initを全サブプロジェクトで実行します。

GKEクラスターの作成

make build

を実行してGKEクラスターをセットアップし、作成したGKEクラスターを指すgcloudコマンドを初期化します。構築までに5分程度かかります。
詳細は0-build-clusterディレクトリにありますが、以下を行っています。

  1. gke_clusterモジュールを利用してクラスタを展開。クラスタを作って潰してを繰り返している際に、GCP側で完全に環境を消しきれていない状況で、再構築時にエラーが発生することがあったので、ランダムな文字列をサフィックスとしてつけている。
  2. GKEクラスタ生成後、生成クラスタ情報をkubeconfigfileに取得。GKE絡みのterraformモジュールを利用する際に必要になる。
  3. locust_connect.shという名でgcloudコマンドを、作成したGKEに向けるスクリプトを生成。Makefile内部で直で実行してしまうと、その実行中のみ有効なだけになってしまうので、一旦シェルファイルに吐き出して実行させている。

deploy/projects/distributed-load-testing-using-kubernetes-locust/0-build-cluster 以下に、GKEの設定情報ファイルとしてkubeconfigが生成され、またgcloudコマンドのGKEクラスタへの初期化用に、gcloud_conf.shというファイルが生成されます。これは以後実行する他のmakeコマンドからも参照されます。

Locustスクリプトの編集

デフォルトでは、locustディレクトリ以下の

  • main.py
  • libディレクトリ以下のpyという拡張子を持つ複数ファイル

ConfigMapに展開し、Locustクラスターから参照できるようにします。main.pyの中に負荷スクリプトを書いて展開してください。またサンプル用の負荷ファイルがmain.pyと同じディレクトリに配置してあるので、中身をコピーしてmain.pyに貼り付ければ利用できます。

Locustクラスターの作成

make a_locust

を実行して、パフォーマンステスト用の locust と必要なコンフィグマップ(ロードテストスクリプトを格納する)をセットアップします。
詳細は2-deploy-locust内部にありますが、

  1. kubernetes, kubectl, helmモジュールで先ほど生成したkubeconfigを利用して、GKEに接続できるように準備
  2. helm_updaterで、必要なhelmリポジトリを取得できるように設定
  3. kubernetes_config_mapリソースを使って、LocustスクリプトファイルとライブラリをConfigMapに展開
  4. helm_releaseリソースを利用して、Locustのhelmファイルを展開。Locustのhelmのパラメータ設定はlocust/values.yamlから取得する。

helmチャートはhttps://github.com/helm/charts 以下が廃止になったので、https://charts.deliveryhero.io/ のものを利用しています。

デフォルトではスクリプトはlocustディレクトリ以下のmain.pyを参照し、ライブラリはlib以下に書かれているpyという拡張子がつくファイルをConfigMapに展開します。

Locustマスターサーバーへの接続(port forwarding)

make locust

これでローカルへのポートフォワーディングが行われます。これで、localhost:8089Locust Masterにアクセスできるようになります。

負荷スクリプトを書き換えて、再度Locustクラスタに展開

make refresh

Scriptの書き換えにはConfigMapを利用しています。そのため手順としては以下となります。

  1. Scriptを書き換え
  2. ConfigMapを更新
  3. Podを更新

これら作業をmake refreshコマンド一回で実施します。terraformによる更新処理が終わり、Locustクラスタが再展開されたら、make locustLocust Masterに接続します。

ローカルで負荷テスト環境

とはいえ、負荷スクリプトが完成するまで、試行錯誤を繰り返すかと思います。そのたびにGKE上で毎回ConfigMapを更新して、クラスターを再展開というのは時間がかかります。

意図する負荷パターンのスクリプトが完成するまでは、ローカルで色々試行錯誤できた方が効率がいいかと思います。そのため、docker-composeを利用して1ワーカースレッドで起動する小規模クラスタをローカルで動かせるdocker-compose.yamlも添付しました。

ローカルでスクリプトを動作させるには

docker-compose up --build --scale worker=1

でクラスター起動させ、localhost:8089Locust Masterにアクセスできます。

参照設定

今回、GKE上のLocust Clusterで、spike_load.pyを使用して10000RPSを生成した設定は以下になります。

spike_load.py は最初に全ユーザー展開し、すべてのユーザーが展開し終わるまでリクエストを投入するのを待ちます。(全ワーカーが同期しているわけでなく、各ワーカー毎でのユーザーになります。)

パラメータ 説明
Locustワーカーのマシンタイプ (Makefile内のMACHINE_TYPE) e2-standard-2
ワーカーのReplicas(values.yamlの66行目) 15
ユーザー数(spike_load.phの15行目、user_amount変数) 10000

この設定で

  • 最初の1秒間のRPSは600前後
  • 15~20秒後には10000RPSに達し、それ以上になります。

ほぼ10000RPSで負荷をしばらく保持する場合は、constant_pacing関数でアクセスのペースを上げるとよいでしょう。

spike_load.pyでは、以下の行でdwell load timeを設定しています。このコードは、user_amountのユーザー数で120秒維持することを意味しています。維持時間は適宜変更してください。

spike_load.py
 target_with_times = Step(user_amount, 120)

ワーカーとユーザーのバランスを調整する方法

低コストで負荷を発生させるためには、できるだけワーカーの数を少なくしたいかと思います。ここでは自分が実際行った、ユーザー数とワーカー数を適切に調整するためのサンプルステップをご紹介します。

spike_load.pyスクリプトを利用して、10000RPSを発生させるのに、試した手順は以下の通りです。

最初のトライ

HPAを有効にして、10台のワーカー、2000人のユーザーからスタートし、Locustクラスタがどのくらいの負荷を発生できるかを確認しました。この場合、Locustは3000RPSを生成し、そこで飽和しました。Cloud LoggingではCPUエラーが発生していないことから、CPUがまだ限界に達していないと考えられます。

2回目のトライ

3倍のユーザー数で10000RPSを生成すると仮定します。ユーザー数を6000に変更し、make refreshを実行、ConfigMapとLocustクラスタを再構築します。結果、ワーカーが自動的に15にスケールアップし、負荷が10000RPS以上になったことを確認しました。

3回目のトライ

ワーカーがスケールする時間を短縮するため、values.yaml で初期ワーカー数を 15 に調整し、make refresh で Locust ポッドを更新します。

まとめ

10000 RPS以上の負荷を生成するクラスタの構成には成功しましたが、1〜数秒で10000RPSに到達するような、スパイクを再現するようなスクリプトは上手くつくれませんでした。どなたか見識がある方がいらっしゃったら教えてください。

比較的容易に負荷生成サーバーは作成できたので、GKE上に負荷サーバーの構築を検討されている方の参考になれば幸いです。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2