こんにちは。SRE部の川崎(@yokawasa)、巣立(@tmrekk_)です。私たちは、ZOZOTOWNのサイト信頼性を高めるべく日々さまざまな施策に取り組んでおり、その中の1つに負荷試験やその効率化・自動化があります。本記事では、私たちが負荷試験で抱えていた課題解決のために開発、公開したOSSツール、Gatling Operatorを紹介します。
はじめに
ZOZOTOWNは非常にピーク性のあるECシステムであることから、常にそのシステムが受けうる負荷の最大値を意識しております。想定しうる最大規模の負荷を受けてもユーザー体験を損なうことなくサービス継続できることをプロダクションリリースの必須条件としています。したがって、新規リリースやアップデート、大規模セールなどのシステム負荷に影響を与えうるイベント前など、比較的頻繁に負荷試験を実施しています。そして、社内でもっとも利用実績のある負荷試験ツールがGatlingになります。
Gatlingとは、Webアプリケーション向けのOSS負荷試験フレームワークです。テストシナリオをScala(Gatling 3.7からはJavaやKotlinもサポート)のDSLで記述でき、結果レポートをHTMLで自動生成してくれます。
本記事で紹介するGatling Operatorは、このGatlingをベースとした分散負荷試験のライフサイクルを自動化するKubernetes Operatorです。
Kubernetes Operatorとは、カスタムリソース(以下、CR)とそのCRにリンクされたカスタムコントローラーによりKubernetesを拡張するための仕組みであり、Kubernetes上で稼働するワークロードのライフサイクル管理の自動化を可能にします。ワークロードの目的の状態を定義したCRをクラスターにデプロイすると、カスタムコントローラーが制御ループを通じてその目的の状態に近づくように制御します。
Gatling Operatorの場合は、分散負荷試験の内容を定義したGatling CRがクラスターにデプロイされると、Gatling CRにリンクされたコントローラーが目的の状態に近づくように制御することで一連の分散負荷試験のタスクが自動化されます。
なぜ開発したのか?
開発の発端は、ZOZOTOWN冬セール対策の負荷試験における課題感からでした。
冬セールはZOZOTOWNにおいて一年でもっともユーザーアクセスが多いイベントです。これを安定的に乗り越えるべく、2021年冬セールから事前にオンプレ・クラウドを横断した大規模な負荷試験を本番相当の環境を使って実施しております。この負荷試験は、機能ごとの単体の負荷試験ではなくユーザー導線に合わせてZOZOTOWNにセール同等のトラフィックを再現し、ボトルネックとなりうる箇所を事前に潰すことを目的としています。なお、今年の2022年冬セール向け負荷試験の詳細については別記事にて紹介される予定です。
さて、この冬セール向けの負荷試験ですが、当然ながら目標スループットを再現するためにはGatling実行用ノードを大量に並べて並列実行させる必要があります。これが単一システムの負荷試験であれば、試験用にチューニングされた一台の仮想マシンからの実行で事足りることが多く、多くても数台並べてタイミングを合わせて実行することで目標スループットを再現できます。ただし、冬セール規模となればそうも行かず、大量のGatling実行用ノードの準備、大量ノードからの実行タイミング調整やレポート生成などさまざまな運用面での課題感がありました。
そこで、2021年冬セール向けの負荷試験では、運用面での課題感を解決すべくAmazon ECSからAWS Fargateをデータプレーンとして利用する方式を採用しました。そこに大量のGatling実行用ノードを並べて分散負荷試験の実行やレポート生成などを自動化しました。これにより当初感じていた運用面での課題はある程度解消されました。ただし、逆にFargateの制約から生ずる課題に直面しました。
- Fargateはオンデマンドでコンピューティングリソースを提供する仕組みであり、タスク実行毎にホストリソース確保と準備処理が行われるため、EC2と比べPod起動までの待ち時間が長くなりがちでした。
- タスク用に予約可能なvCPUとメモリの選択の幅が狭く、したがって目標スループットを再現するためには必要ノード数が多くなりがちになりました。これによりFargateの同時に実行可能なタスク数の上限に達しやすくなり、目標スループットを安定的に再現できないという課題がありました。なお、当時と比べるとFargateのインスタンスあたりの性能は向上し、同時に実行可能なタスク数の上限も上がっていることから問題は緩和されているといえます。
これらの課題を解消すべく、2022年冬セール対策負荷試験に向けてGatling Operatorを開発することになりました。これにより、分散負荷試験の自動化はもとより、Gatling用Podに柔軟にノードリソースの配分ができるようになりました。また、分散負荷試験がマニフェストで宣言的に定義できるようになったことも大きなメリットといえます。
Gatling Operatorの処理概要
Gatling Operatorの処理概要を簡単に説明します。利用者が分散負荷試験の内容を定義したGatling CR(後述)をクラスターにデプロイすると、カスタムコントローラーにより、次のような一連のタスクが自動実行されます。
1.Gatling Runner Jobの作成
・Gatling Runner Jobは、指定された並列実行数(Parallelism)分のGatling Runner Podを作成します
・各Gatling Runner Podでは、Gatlingテストシナリオを実行して、出力された結果レポート用ログファイル(simulation.log)をクラウドストレージにアップロードします。次の「Gatling Runner Podのマルチコンテナー構成」でGatling Runner Podについてさらに詳しく解説します
2.Gatling Reporter Jobの作成(オプショナル)
・Gatling Runner Jobが完了すると、Gatling Reporter Jobを作成し、そのJobがGatling Reporter Podを作成します
・Gatling Reporter Podはすでにクラウドストレージにアップロードされた全Pod分の結果レポート用ログファイルをローカルファイルシステムにダウンロードします。そして、すべてのログファイルを元に集約したHTML結果レポートを生成し、それをクラウドストレージにアップロードします
3.試験結果をメッセージ通知プロバイダーに送信(オプショナル)
・前のすべてのステップが完了すると、試験の実行結果をメッセージ通知プロバイダー用Webhookに送信します
4.関連リソースのクリーンアップ(オプショナル)
・すべてのステップが完了すると、Gatling CRとその関連リソースであるJobやPodを削除します
Gatling Runner Podのマルチコンテナー構成
分散負荷試験のメインワークロードであるGatling Runner Podのコンテナー構成について解説します。
上図のようにGatling Runner Podはマルチコンテナーで構成されています。gatling-runnerによるGatling負荷試験の実行以外に、gatling-waiterとgatling-result-transfererでそれぞれ次のような前処理と後処理が実行されます。
続きはこちら