Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

秒間10万メッセージをさばけ! リアルタイム対戦バトルゲームを支える負荷試験の挑戦【Developers Boost】

【A-2】リアルタイム対戦バトルゲームを支えるリアルタイムサーバの負荷試験のリアル

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2019/01/21 11:00

 12月15日、翔泳社主催の若手エンジニア向けカンファレンス「Developers Boost(デブスト)~U30エンジニアの登竜門~」が開催された。企業の中核を担う30歳以下(U30)の若手エンジニアたちが登壇。その知識やノウハウを惜しみなく公開した。本セッションで取り上げた「Arkサーバ」は、gumiのリアルタイム対戦ゲームを支えるリアルタイムサーバだ。対戦バトルゲーム「ドールズオーダー」でも、他ユーザーとの対戦時の通信処理に本サーバが活用されている。Arkサーバの負荷試験における試行錯誤の歴史を、エンジニアの叶若帆氏がふり返った。

株式会社gumi Technical Strategy & Development 叶 若帆氏
株式会社gumi Technical Strategy & Development 叶 若帆氏

システムのQoSを把握するために、負荷試験は極めて重要

 Arkはgumi社が自作したErlang製のリアルタイムサーバだ。通信処理を高速化するため、自社ゲームに最適化したシンプルなプロトコル設計となっている。ゲームロジックを持たず、Pub/Subの役割のみを担う。

 gumiが開発した対戦バトルゲーム「ドールズオーダー」では、複数のユーザーが対戦する際にルームという機能が用いられる。マッチングされたユーザーが同じルームに入り、お互いの状態を同期しながら対戦を行う。その機能を実現しているのがArkによるPub/Subなのだ。

 この前提を共有した後、叶氏は「なぜ負荷試験が必要なのか」について解説した。

 「システムのQoS(Quality of Service)を把握するには、負荷試験を行う必要があります。システムのレイテンシーやスループットがどれくらいなのかを把握しなければ、ユーザーに安心してサービスを提供できません。

 Arkはゲームを支えるうえで特に重要なサーバのため、リリース前の段階でも負荷試験を実施していました。しかし、リリース後に機能追加やバグ修正などを行ったため、再度負荷試験をする必要が出てきたのです」

 負荷試験を行うにあたり、まず検討されたのはインフラ構成だ。サーバをAWS上に配置し、Arkサーバと負荷クライアントを同じネットワークから通信させた。これにより、ネットワークがボトルネックにならないようにしたという。

 「インフラ構成を決めたら、次は負荷クライアントの用意です。Arkサーバでは自作のプロトコルが用いられているので、一般的な負荷試験ツールは使えません。そのため、私たちはツールを自作しています」

 前回の負荷試験ではPython製の負荷クライアントが用いられた。だが言語の特性上、CPUの利用効率が悪かったため、今回は不採用となったそうだ。メンテナンスのしやすさも考慮し、今回の負荷試験ではArkでも用いられているErlangで負荷クライアントを実装する方針となった。

 負荷クライアントの名は、Flood(洪水の意味。方舟の名を冠したArkに対し、大量の負荷をかけることから)に決定したという。

「何がボトルネックか」を特定し、性能を改善する

 負荷クライアントの完成後、負荷試験がスタートした。だが、ここで衝撃の事実が判明する。なんと前回の負荷試験の2割程度しか処理できなかったのだ。いったい何が原因なのか。究明のための戦いが始まった。

 ログファイルの分析やインフラチューニング、OSのネットワークバッファチューニングなどを行ったものの、状況は改善しなかったという。最終的には、プロファイリングツールを用いて「どんな関数が呼び出されているか」の調査が行われた。ここで、ようやく原因特定に至ったそうだ。

 「なんと、デバッグ用の関数がたくさん呼び出されていました。つまり、私はデバッグモードをオンにしたまま負荷試験をしてしまったのです(笑)」と叶氏はちゃめっ気たっぷりに話す。

 デバッグモードをオフにし、負荷試験が再開された。すると、前回の負荷試験と同様に秒間10万メッセージをさばくことができたという。セッション数の増加スピードも安定しており、メモリの使用量も1GB未満。目標のQoS測定をクリアした。だが、ここで負荷試験は終わらなかった。なぜだろうか。

 「その理由は、『もっと性能を出せるでしょう』と上司からのメテオフォールが降ってきたからです(笑)」と叶氏は笑顔で語る。さらなるパフォーマンス改善のため、処理の最適化が検討されていった。

 「Ark内部のプロセスは、メッセージを受け取るたびにオンメモリのストレージにある共有カウンターをインクリメントします。しかし、この集計方法では10万回のメッセージにつき10万回の更新が発生します。ここを改善したいと考えました」

 改善策はこうだ。共有カウンターを毎回インクリメントする代わりに、プロセス内部にカウンター変数を作ってその値を加算する。そして、一定の頻度で加算後の値を共有カウンターに反映させることで、更新頻度を減らすのだ。しかし、この方法ではカウンターの差分計算やリセットの処理などが各プロセスのボトルネックになり、うまくいかなかった。

 叶氏は別の方法で、処理性能の改善を模索する。これまでの分析では、Arkサーバの平常稼働時に異常な動きは見当たらなかった。そこで、さらに限界以上の負荷をかけ、サーバのクラッシュ分析を行った。するとサーバがクラッシュする際に、プロセス間の通信タイムアウトエラーが頻発していることが判明したという。

 Arkでは通信のセッションを維持するために内部で複数のプロセスを立てている。そのなかに、セッション全体のライフサイクル管理・TCPメッセージのルーティングを担当するセッションプロセスと、UDP通信のライフサイクルを管理するUDPセッションプロセスがある。この2プロセス間で、タイムアウトエラーが発生していた。

 Arkサーバへの負荷が大きくなると、全体を管理するセッションプロセスのタスクが多くなる。このとき、UDPセッションプロセスがセッションプロセスを同期呼び出しすると、レスポンスの待ちが発生する。そして、一定時間が経過しても返信がない場合、UDPセッションプロセスがタイムアウトエラーを起こしてしまうのだ。

 「この課題を解決するため、UDPセッションプロセスが行っていた同期呼び出しを、すべて非同期呼び出しに変更しました。この結果、サーバへの負荷が大きくなった場合でも大量のタイムアウトがなくなり、Arkサーバが秒間あたりに処理できるメッセージ数が10万から11万に改善したのです」

「負荷試験においては、上図のような点を守ることが大切」と叶氏は結んだ。
「負荷試験においては、上図の点を守ることが大切」と叶氏は結んだ。

 サービスの処理性能を把握し、可用性をさらに高めていくために、負荷試験は欠かせない工程である。本セッションは、その重要性やノウハウが十分に伝わるものとなった。

お問い合わせ

 株式会社gumi

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5