スマートフォン向けゲームの負荷試験で必要なもの

本記事は、[サムザップ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/sumzap) の12/15の記事です。

この記事では、スマートフォン向けゲームの負荷試験を実施するにあたり必要な準備を記載します。

これまでいくつかのゲームで負荷試験を実施し、その都度準備するものを確認したり、ツールを作り直したり、負荷試験期間を見積もったりと同じようなことを繰り返してきたので、自身の備忘録として残しておきたいと思います。

# 要約
### 必要なもの一覧
|項目|概要|
|:--|:--|
|各種指標|RPSやDAU等負荷試験の目標とする（もしくはそれを導出するための）指標|
|負荷試験対象サーバー|負荷試験対象のサーバー及びその環境構築（CI/CD含む）|
|アタックサーバー|負荷をかけるツールを動作させるサーバー及びその環境構築（CI/CD含む）|
|アタックツール|負荷をかける（ユーザーのアクセスを模倣するための）ツール|
|モニタリングツール|サーバーのリソース状況をモニタリングするためのツール|
|APM|アプリケーションのパフォーマンスを監視するためのツール|
|その他|その他必要そうなもの|

# 各種指標
負荷試験のゴールです。
弊社の場合は、主にRPS(Request per Second)を指標とし、その指標が達成できるようにシステムのボトルネックやアプリケーションのパフォーマンスを調査・改善していきます。

目標のRPSを決めるために、想定されるDAUやアクセス傾向が近いと思われるゲームの実績等も確認します。

# 負荷試験対象サーバー
いわずもがな負荷試験の対象アプリケーション。

ポイントとしては、

- 本番環境と同等のもの
  - 費用が非常にかかりますが、縮退環境では発見できないボトルネックが見つかるケースがあるため、可能な限り本番相当の環境で実施するのがオススメ
  - ログの出力やデバッグ設定等も本番相当に設定すること
- アーキテクチャー的に水平方向にスケール増減しやすくすること
  - ゲーム系はリリース当初やプロモーション時にアクセスが集中し、その後アクセスが落ち着く傾向があり、柔軟にスケールできる仕組みがないとインフラや人的リソースがかさんでしまうため

# アタックサーバー
負荷をかける側のサーバー群。
負荷試験は、

- 負荷をかける
- 分析する
- 改修する

のサイクルを如何に速く回せるかが重要なので、アタック側もCI/CD環境もしっかり用意すると良いです。
またアタック側もかけたい負荷によってスケールできる必要があります。

# アタックツール
負荷をかけるツール。
これまでいくつかの変遷がありますが、現在はPython製のLocustを利用しています。

### 主な選定理由
- シンプルに分散実行が可能
- 最低限の集計機能が用意されている
- コードで管理できる
- Pythonでかけるので、やりたいことが大体実現可能

### 用意している仕組み
弊社では各機能担当にシナリオ（再現したいユーザーアクセスを記述したもの）を用意してもらうため、シナリオをなるべく簡単に作成できるように以下のような仕組みを用意しています。

|項目|説明|
|:--|:--|
|ディレクトリ構成・クラス設計|担当者が迷わず実装出来るように分かりやすく|
|コード自動生成ツール|必要なファイル構成はどのシナリオでも基本的に同じためテンプレートを自動生成|
|ユーザー切り替え|基本的にシナリオは、1ユーザーのアクセスを模倣するだけで事足りますが、機能によっては他のユーザーとのやりとりが必要になる場合（例えばフレンド機能等）があり、そういったシナリオを表現する場合に必要|
|シナリオ切り替え機能|シナリオの設定がソースコードに記述されているため、シナリオを変更するためにはデプロイが必要だが非効率なため、デプロイなしに変更できる仕組みがあると良い|
|クライアントDB機能|ゲームアプリでは、クライアント側でユーザー情報を保持し、各種ゲームロジックを実行、結果を送信するような仕組みのため、シナリオ上に固定のリクエストパラメータを指定するだけでは対応できないケースがあるため<br>またそのDBにデータを格納するための機能や簡単に取り出して利用できる機能も必要|
|負荷（RPS）を指定できる機能|負荷試験ではゴールとなるRPSを達成するために実施するが、単純にシナリオを記述すると試験対象のサーバー及びアタック側のパフォーマンスによって変わってしまい、実行時のパラメータを調整する手間が発生してしまうため。<br>弊社では「SequentialTaskSet」と「wait_timeにconstant_throughput」を利用し、1API1Taskとすることで実現しています|
|指定ユーザーでの実行機能|予め作成しておいたユーザーデータを利用してシナリオを組みたい場合に必要<br>セットでDBのバックアップ＆リストア機能も必要|
|ロギング・集計機能|Locustで予め用意されているもので不足がある場合に追加<br>弊社ではシナリオのデバッグ等のため、リクエスト&レスポンスのログをrequestイベントを利用して出力|

# モニタリングツール
負荷をかけた際に各種サーバーリソースを可視化するツール。
主にサーバーリソースのボトルネックを発見するために利用します。
また運用時にも監視ツールとして利用すると思いますので、この時点でしっかり用意することをオススメします。

こちらもこれまでの変遷がありますが、現在はDatadogを利用することが多いです。
可視化できれば、Cloud WatchでもCloud Monitoringでも何でも大丈夫です。

かつてElasticsearch+Kibanaで可視化出来るようになって、すげぇー！！って喜んでいた時代が懐かしい…便利なサービスはどしどし活用して、よりビジネス的にコアな部分に集中できるようにしていきたいですね。

# APM
負荷をかけた際にアプリケーションのプロファイリング・可視化ツール。
アプリケーション上のボトルネック（どこに時間やCPU等リソースを消費しているか）を発見するために利用します。

弊社は主にサーバーサイドをPHPで開発しており、以前はNewRelicを活用させてもらっていましたが、現在はDatadogのAPMを検討中です。

何度もコールされて時間がかかっている処理や、遅いSQL等を実際に負荷がかかっている状態でプロファイリング出来ることが重要です。
ローカルでのプロファイリングももちろん重要ですが、高負荷時のみ発生するような事象はローカルで再現することは難しく、こういったツールを負荷試験環境及び本番環境で利用すると、問題が発生した際に素早く原因を切り分けできる場合があります。

# その他
その他準備しておいた方が良いもの

|項目|説明|
|:--|:--|
|データ生成ツール|ボトルネックになりやすい箇所のひとつとしてDBがあると思いますが、DBの処理速度はレコード件数によるところが大きいため、負荷試験前に予め運用時に想定される件数分のユーザーデータを生成しておくために利用します。<br>負荷試験でデータを用意していなかったために、負荷試験はパスしたものの、本番ではDBが詰まってしまった！！なんてことがないようにしたいですね。|
|本番相当のマスターデータ|シナリオを作成する際にも必要ですし、本番で想定されるマスターデータが実はエンジニアが想定していたものと乖離していた！なんてことがないように予め準備してもらうのが良いと思います。|

# まとめ
スマートフォン向けのゲームですと、リリース時が一番高負荷になりやすいポイントのひとつで、リリース後負荷に耐えられず即メンテナンス、数日後に再オープン…場合によっては、そのままクローズ。。なんてアプリもいくつか見てきたので、この記事がそんなことがないように安定・安心のリリースに貢献できれば嬉しいです。

明日は、@Gaku_Ishiiさんの記事です。お楽しみに〜♪