モンストの新機能実装にAgonesとOpen Matchを採用しました
モンストサーバチームの徳森です。
モンスターストライクでは2024/8/9にスクランブルユニバースをリリースしました。
スクランブルユニバースは最大8人でリアルタイムにクエストのクリア時間を競うモードです。
これを実現するためには、条件に合わせたユーザーをマッチングする仕組みと、ユーザー間の通信やゲームの進行を制御するゲームサーバを管理する仕組みが必要です。
今回はこれらの仕組みを構築するために、Open MatchとAgonesを採用しました。この記事ではその構成について記します。
構成の全体像
以下がスクランブルユニバースにおけるバックエンドのおおまかな構成図になります。
Open Match、 Agonesを含むスクランブルユニバース用のバックエンドは通常のアプリケーションサーバとは別のGoogle Cloud Project上のGKEに構築されています。
アプリケーションサーバは直接Open MatchやAgonesのAPIを呼び出さずに、その間にあるGame FrontendのAPIを経由します。
各コンポーネントについて
図中に登場するコンポーネントについて簡単に説明します。
より詳細なものは、Open Match関連はこちら、Agones関連はこちらを参照してください。
Open Match Core
Open Match関連のコンポーネントの中でもOpen Match FrontendやOpen Match Backend等Open Match の中核を担う機能群で、基本的に手をいれる必要はなくinstallされたものをそのまま使うことができます。
Agones System
allocator、 controller、 extensionsから成るAgonesのコンポーネントです。
今回の話で重要なのはallocatorで、これが提供するAPIを呼び出すことで、Agonesが管理するゲームサーバのエンドポイントを得ることができます。
Game Frontend
Open Matchでのチケット発行や、Agones allocator経由で利用可能なゲームサーバのエンドポイントを得るためのAPIを提供します。
アプリケーションサーバはこれらを呼び出すことでユーザーからのリクエストに応えます。
Director
DirectorはOpen Matchに関連するコンポーネントの一つです。
マッチングの要求と、成立したマッチングに対するゲームサーバの割り当てを、Open MatchとAgones allocator APIを用いて実現します。
ExternalDNS
Agonesの返すゲームサーバのエンドポイントはIPv4なので、IPv6対応のためにdirectorがFQDNを返すようになっています。
このためのnode別のDNSレコードを作る役目をExternalDNSが担っています。
Agones側の設定で ExternalDNS
を指定することも可能ですが、GKEでは未対応で、さらにリンク先Issueに書いてある bc.googleusercontent.com
も永続的に有効である保証はないため、この方法を取っています。
インフラについて
構成図に示されるように、このシステムは複数のクラスタが存在するマルチクラスタ構成をとっています。
これは負荷試験の結果、今回の実装ではAgones Allocator Serviceによるゲームサーバのallocateがボトルネックとなることがわかったため、その負荷を分散させることを目的としています。
負荷分散のために複数のクラスタに分けたAllocator Serviceは、Network Endpoint Group(NEG)を用いて一つのロードバランサに束ねることで、単一のエンドポイントから利用することを可能にしています。
serviceにNEGを設定するには、annotationsへの記述を行うだけでよく、AgonesではこれをHelm Chartのvalues file経由で指定することができるため、以下のように記述します。
allocator:
service:
annotations:
cloud.google.com/neg: '{"exposed_ports": {"80":{"name": "NEG_NAME"}}}'
あとはこれによって作られたNEGをロードバランサのバックエンドに指定するだけで完了です。
Open Matchもマッチングする範囲を分割することで複数のクラスタに配置することが可能ですが、仕組みが複雑になりますし、試験の結果シングルクラスタでも十分負荷に耐えうる性能を持っていることが確認できたため、一つ目のクラスタだけに配置しています。
負荷試験と結果
今回のシステムでは、すべてのユーザーが最大でも10秒以内にマッチングを終えるという要件がありました。
これを元に負荷試験では秒間800チケット発行時に全てのチケットが10秒以内にアサインされるという目標を立てていましたが、この構成で全てのチケットが6秒以内にアサインされるという結果を得ることができました。
ただし、Open Matchによるマッチングの負荷や速度はdirectorやMatch Functionに大きく依存するので、複雑なマッチングを行う場合はより時間がかかる可能性があることを意識する必要があります。
リリース後、想定を大きく超えた数のゲームサーバが起動する程の負荷がありましたが、ゲームサーバのallocateがネックになることはありませんでした。
チケットのアサインについても、実際の環境では負荷試験の時よりもゲーム時間が長くなったことで1秒間に発行されるチケット数が減り、殆どの場合1秒程度で完了しました。
まとめ
今回の記事ではOpen MatchとAgonesを採用したマッチメーキングとゲームサーバの管理を行うシステムについて記しました。
Open Matchはマッチングの実装に依存しますが、シングルクラスタでも十分な性能を持っており、不足を感じる場合でも実装を工夫することでマルチクラスタでの負荷分散が可能な、扱いやすいフレームワークだと思いました。
Agonesは基本的にマルチクラスタ前提で考えたほうがいいと思いますが、今回紹介した方法を取ることでクラスタの増減を簡単に行えるようになるため、マルチクラスタ化による運用のハードルはそれほど高くないと思います。
この話がなにかの役に立てば幸いです。
Discussion