複数人のプレイログを収集する

ごましお氏:続いては、複数人のプレイログを収集するフェーズです。例えば、開発チーム内でのプレイ会とか社内プレイ会みたいな、なるべく大人数がプレイするタイミングでログを収集します。

自分でプレイしてログを収集するのとは目的が違っています。ここでは、1ユーザーあたりのRPSを測定すること、それからAPI呼び出しの全体の割合を把握することを目標とします。なるべく多くの人数でプレイしたログが収集できると、それだけ精度の高い情報が得られて、以降の試験の精度も高くなることになります。

試験を実施する

続いて、いよいよ試験を実施するフェーズになります。作成した試験クライアントをデプロイして、実際に負荷をかけていくまでの流れを説明します。

まずは、ビルドした試験クライアントのバイナリを含んだコンテナイメージを作成します。社内では、GitLabでソースコードのバージョンを管理しているので、GitLab CIを使ってイメージをビルドして、GCPのArtifact Registryにプッシュしています。

それから、コンテナイメージはGKE(Google Kubernetes Engine)の環境で動かすので、そのためのマニフェストを生成します。マニフェストはHelmを使ってテンプレート化していて、生成したものはCloud Storageにアップロードしておきます。

最後にSpinnakerパイプラインでパラメーターを指定して、生成したマニフェストをGKE環境にデプロイする流れになっています。

(スライドを示して)ちょっと小さいかもしれないんですが、左側の黒い背景の部分がHelmのテンプレートから生成したマニフェストで、右側がSpinnakerパイプラインのパラメーター設定になっています。

マニフェストの状態でいくつかまだ変数的な箇所が残っているんですが、ここにSpinnakerから渡されたパラメーターが入ってきます。例えば実行回数であったり、対象の試験シナリオであったり。想定ユーザー数みたいなものはパラメーター化しておくことで、イメージをビルドし直したりマニフェストを生成し直したりをその都度やらず、いろいろな試験パターンを試せるかたちになっています。

試験結果を評価する

続いて、試験が実施できたら、その試験結果を評価するフェーズです。評価に用いる指標は、主にPrometheusやBigQueryやクラウドモニタリングから集めたメトリクスをGrafanaで可視化するようにしています。

試験の評価は大きく2つに分けて考えています。1つは、適切な負荷がかけられているかという試験条件的な観点、もう1つが、結果の品質に問題がないかという観点です。

試験条件のほうは、RPS、APIのカバー率、アクセス傾向、試験の継続時間、入会の速度などといった項目で見ています。これらを満たしていないと「そもそも正しい負荷がかけられていませんよ」ということなので、まずはこれらをきちんと満たすよう、パラメーターを調整したりシナリオを修正したりします。

評価のほうは、HTTPのステータスやレイテンシ、高負荷環境でのプレイ感などといった項目を、1つ目の試験条件を満たせた上で確認します。そして、最終的にそのゲームの品質として問題ないか評価します。

こちらに問題があれば各項目を満たすよう、アプリケーションを修正するなり、仕様の調整が必要なら調整するなり、インフラのスペックを見直すなりをしていくという流れになります。

(スライドを示して)こちらの画面は、評価に使うGrafanaの画面イメージです。これは全量の試験結果ではないですが、例えば画面の左上から見ていくと、ユーザーが2,409人分動いていて、APIサーバーのポッドが7台スケールしていて、カバー率がどうかとか、アクセス傾向がどうかとか、RPSがどうかとか。そういった試験条件に当たる項目が表示されています。

その下では、ステータスが200じゃないリクエストがどのぐらい発生していたかとか、テールレイテンシがどの程度かとか、クライアントから見たレイテンシがどの程度かといった評価内容が確認できるようになっています。

実際は作るゲームによって見る項目も違うので、このダッシュボード自体の作成や管理も負荷試験環境の準備に含むことになります。

規模を増やしながら繰り返す

そして、この試験の実施と評価を、規模を増やしながら繰り返していきます。

「いきなり最大の規模でやらないのはなんで?」と思う方もいるかもしれないですが、これはコストを最適化するためです。ゲームをローンチする時は、基本的にマーケティングの部署とコミュニケーションを取って、そのゲームはどのぐらいのユーザーさんがプレイしてくれそうかという規模を見積もります。

負荷試験は「その見積もりの最大の規模のアクセスが来ても大丈夫だよね」という状態までやるんですが、大規模な負荷試験は、当然ですがお金がすごくかかります。アプリケーションを動かすサーバー費用もかかるし、試験クライアントを動かす環境の費用も、規模が大きければその分必要になってしまいます。

しかし、まだ売上を上げていないローンチ前のゲームの負荷試験で、やたらめったらサーバー費用を使うのは非常にもったいないです。小さい規模でも見つかる問題は小さい規模の試験で潰しておくようにすると無駄が出にくく、効率的な負荷試験を行うことができます。なので、負荷試験は繰り返し実施しやすいこと、スケールイン、スケールアウトが容易な構成になっていることが重要であると考えています。

規模によってどういう問題が見つかりやすいかというと、ミニマムな規模でも起きがちな問題は、例えばそもそもアプリケーションエラーが潰しきれていないことだったり、indexの設定などクエリのミスだったり、キャッシュなどのTTLの設定ミスなどです。このあたりは、小さい規模でも比較的発見しやすいです。

規模が大きくなるにつれて起きやすい問題は、データベース関連なら、ロックが起きやすくなってきたり、GoogleでCloud Spannerを使っているならホットスポット起因でデータベースの詰まりが発生してきたり、ネットワークを流れるデータの転送量が大きくなってレイテンシが悪化したり。

対戦ゲームなどであれば、マッチングが適切に処理されなくなったりなどがあります。こういったものは、規模を増やしていくことで露見しやすくなる問題かと思っています。

試験の規模を柔軟に変更できるようにするために、試験に使う環境のスケールイン、スケールアウトをパイプライン化しておくと便利です。試験クライアントのデプロイフローでも紹介しましたが、それと同じように環境自体のスケールもSpinnakerからパラメーター指定で実施できるようにしています。

具体的にはGKEクラスタそのものであったり、アプリケーションのポッド数はHPAで管理していますがその値であったり、Cloud Spannerデータベースのノード数であったりという部分をそれぞれパイプライン化しておいて、使う時に使う分だけ立ち上げられるよう工夫しています。

大切なのは「正しい負荷をかけて、適切に評価すること」「効果的・効率的に試験すること」

まとめです。ローンチ時のサービス品質を保つために必要不可欠な負荷試験について、コロプラでのやり方を紹介しました。正しい負荷をかけて、適切に評価すること。それから、効果的・効率的に試験することを大事にしているという内容でした。

以上です。ありがとうございました。