Now in REALITY Tech #60 サーバの負荷試験環境を構築した話

入社半年ほど経過しまして、最近はDIYにハマっているREALITY プラットフォーム事業部サーバチームのdaidaiです!

今回はREALITYアプリのサーバ環境に負荷試験の仕組みを導入したので、導入過程や構成、課題感などをご紹介していきます。

負荷試験環境を作った経緯

まず現在REALITYでは負荷試験環境が存在せず、負荷に懸念がある処理でも実際に本番リリースするまでAPIのパフォーマンスやボトルネックが把握できない状況でした。また新規にリリースする変更以外にも、イベントやキャンペーンの影響でリクエストがスパイクした際の既存APIなどのパフォーマンス状況も含め、サーバのパフォーマンスを包括的に把握できると、嬉しいことがありますよね。

また、特定のAPIに存在する問題について共通認識を作れることも重要だと思うので、まずは最小構成での負荷試験ツールを導入するに至りました。

技術選定

まずは以下の選定基準をベースに技術選定 & アーキテクチャを考えていきました。

  1. 太ましい構成にしない(最小構成で)

  2. 簡単に扱える

  3. 利用例がたくさんある

  4. 複数のマシンから同時分散的に負荷をかけられる

  5. 後から負荷試験結果を誰でも見れる

まず初期は運用コストを下げたいのと、シンプルな構成で使えるものにしたいという思いが強いので1、2番目の基準は結構大事にしています。また1台のマシンでは再現できないような高負荷にさらされるAPIもあるため、4の条件も大事です。

巷でよくあるツールを挙げてみると、Locust、vegeta、wrk、Gatlingなどがあると思いますが、私たちは上記の選定基準を踏まえてLocustを採用することに決めました。

LocustはPythonで実装されている負荷試験OSSであり、多数の利用例があります。分散負荷テストにも対応しており機能もシンプルです。また、boomerというプラグインを使うとGoで負荷試験シナリオが書けるようになり、REALITYのAPI本体と同じ言語で記述できます。さらにLocustは負荷試験の結果をHTMLでグラフィカルに出力 & 保存できるため、採用に至りました。

Boomerについて

まずLocustの仕組みについてですが、Locustは大きく分けてMasterとWorkerと呼ばれる2種類のアプリケーションがあります。Masterが負荷試験全体のコントローラ的な役割を果たし、Workerはその名の通り、負荷試験シナリオが実際に動くアプリケーションとなります。

WorkerはデフォルトではPythonで負荷試験シナリオを書く必要がありますが、インターフェースを満たすと他の言語でも記載することができます。Boomerというプラグインは、そのインターフェースを満たした上でGo言語でシナリオを記述することができるツールです。これも簡単に導入できそうかつ、運用コストもなさそうだったので採用に至りました。

https://github.com/myzhan/boomer

アーキテクチャ

最終的に以下のような構成で負荷試験環境を構築しました。

負荷試験ツールのアーキテクチャ

初期は最小構成で、ということで開発環境の既存APIが乗っかっているGKEクラスタ内で動かす構成にしています。この部分はLocustが動く専用のGKEクラスタを立てたり、k8sのTaintsとTolerations機能を使ってLocust部分だけ別ノードだけ動かすような構成に後から変更できます。

使い方としては、まず後述する負荷試験シナリオテンプレートをもとにシナリオを作成し、事前に用意した負荷試験実行シェルをローカルから叩きます。すると自動的にMaster/Workerそれぞれのアプリケーションのコンテナイメージがビルドされ、GKEに反映されます。負荷試験が終わると、自動生成されるHTMLをGoogle Cloud Storageに保存し、そのリンクをSlack通知するようになっています。

負荷試験のシナリオも後から見返せるように全てGithub上で管理する想定です。

負荷試験シナリオのサンプルを用意した話

今回はできるだけチームメンバーの負荷試験ツール利用の敷居を下げるため、負荷試験シナリオのサンプルコードを用意しています。

内容としてはHTTPクライアント生成や、サーバ内部のトークン情報、またREALITYのGoのAPIサーバで共通利用しているモジュールを利用するための設定などが入っています。

新たに負荷試験シナリオを作成する際は、そのサンプルをもとに改変すれば毎回面倒な手続的なコードを書かずとも済むという形です。サンプルコード周りはチームメンバーの声も聞きつつ、柔軟に改善できていけたらなと思います。

実際に実行してみた結果


用意したサンプルの負荷試験コードを実行した結果を貼ってみます。
事前に用意した負荷試験実行シェルを実行してしばらく待つと、まず下記のようにSlack通知が来ます。Locustが自動でGoogle Cloud Storageに保存した負荷試験結果のHTMLファイルのリンクですね。

負荷試験完了通知

通知に記載されているリンクを開くと下記のように、定義した負荷試験メソッドごとにリクエスト数は失敗数、平均レスポンス時間等がわかるようになっています。

負荷試験レポートスクショ.1

今回はサンプルのため、わざと失敗する処理も組み込んでいるのでFailureのレートが高くなっています。

負荷試験レポートスクショ.2

今後の展望とまとめ

今回は、PoCを兼ねてとりあえず導入してみたという段階です。まだ負荷試験をするステップを実際の開発フローに組み込めていないので、いかに上手く組み込むか、が今後の課題です。

どういうタイミングでどんな設定で負荷試験を行い、どうなればゴールなのか、がまだ曖昧なので、そのあたりの基準も決めつつ負荷試験を行う文化醸成ができたらなと思っています。また、最終的にはパフォーマンス的な意味でのサーバの改善点を炙り出して、安定性向上に寄与することが負荷試験の目的なので、早く目に見える成果を出していきたいところですね。

弊社ではそういったサーバのパフォーマンス改善や、クラウドインフラ(GCP)面などからREALITYをヌルサクにしていくことに興味があるエンジニアを大募集しています!


以下のGoogle Formからスカウトを待つこともできますので、是非ご応募ください!
https://docs.google.com/forms/d/e/1FAIpQLSeIJrmkWuk-MIpz5jGpQvkASvM7-krypPTF0fgNAaEI9OVUbQ/viewform