
Amazon GameLift を導入してみた話
新規開発中プロジェクト所属の美濃です。
AWS に含まれるサービスのひとつ「GameLift」をプロジェクトに導入したので紹介します。
https://aws.amazon.com/jp/gamelift/
Amazon GameLift とは
Amazon GameLift とは、マルチプレイヤーゲーム用のクラウドサーバーを管理してくれるサービスで、次のようなサービスで構成されます。
- 開発者はビルドを用意するだけで、あとはフルマネージドな GameLift Hosting
- サーバーリソースの管理、ゲームサーバー(※後述)管理、およびその最適化のみ提供する GameLift FleetIQ
- マッチング機能を提供する FlexMatch
Fleet (GameLift Hosting で使われるサーバー管理システム) および FleetIQ はセッションベースのマルチプレイヤーゲームに最適化されており、レイテンシーやコスト、スポットインスタンスの中断率などから総合的に判断してインスタンスを割り当てます。スポットインスタンスとはいわば「空きサーバーの間借り」であり、中断のリスクと引き換えに安価で使うことができます。中断のリスクがあるとはいえ、 Fleet / FleetIQ によって中断しにくいインスタンスが選択されやすくなっているので、ほとんど気にすることはありません。

開発者から見た GameLift Hosting の弱点
当プロジェクトでは当初 FlexMatch + GameLift Hosting を使用してC#で開発していましたが、以下のような弱点がありました。
GameLift Hosting の弱点1: プロセスモデルを強制される
GameLift Hosting は1プロセスが1ゲームを表す前提でデザインされています。ゲーム開始時にサーバープロセスが1つ立ち上がり、ゲーム終了と共にプロセスが終了するイメージです。プロセスは1つのインスタンス内に最大50個立ちます。このような「プロセスモデル」の実装は C# のサーバーでは一般的ではありませんし、ゲームを実装する際には全体で共通のはずのマスタデータをそれぞれに読み込まなければならないなど、様々なオーバーヘッドが付きまといます。
GameLift Hosting の弱点2: 立ち上がりが遅い
GameLift Hosting を使用する場合、ビルドをアップデートしてからサーバーが立ち上がるまでにおよそ30分かかります。仕組み上、既に動作しているサーバー上に修正したビルドをデプロイし直すことができないため、実装を修正するたびに Fleet を作り直すのですが、そのたびに30分待たされることになります。
GameLift FleetIQ の導入
上記のような GameLift Hosting の弱点を回避しつつ GameLift の強みを享受するため、当プロジェクトでは GameLift FleetIQ を使用することにしました。GameLift 側で用意されたインスタンスにプロセスが立てられる GameLift Hosting に対して、GameLift FleetIQ は純粋なインスタンス管理サービスとして機能します。大雑把に言えば、GameLift FleetIQ は EC2 AutoScaling グループにセッションベースのゲームに最適化された機能を追加したサービスです。GameLift Hosting に比べて自由度が高い反面、自分たちで管理しなければならないものが多くなっています。
動作
GameLift FleetIQ が管理しているインスタンス群はゲームサーバーグループと呼ばれます。ゲームサーバーグループに含まれるゲームサーバーは「使用可能 (AVAILABLE)」「予約済み (CLAIMED)」「使用中(UTILIZED)」というステータスを持ち、AWS SDK を通じて操作します。GameLift FleetIQ は、全体における使用可能なゲームサーバーの割合が一定以上に保たれるようにインスタンス数をスケーリングしてくれます。なおゲームサーバーという名前ですがサーバーインスタンスと1:1で対応するような概念ではなく、同一のインスタンス上から複数のゲームサーバーを登録できるため、ゲームセッションと言ったほうが正しくイメージできるかもしれません。動作の流れは次のようなイメージです。
- GameLift FleetIQ 管理下で確保されたインスタンスで、起動テンプレートによってサーバープロセスを起動します。
- サーバープロセスから SDK の RegisterGameServer を呼び出すことで、ゲームサーバーを使用可能として登録します。
- マッチングサービスなどから ClaimGameServer を呼び出すと、使用可能なゲームサーバーの情報が1つ返されます。このとき、最初に書いたようにレイテンシーやコスト、スポットインスタンスの中断率などから最適なゲームサーバーが選ばれます。この段階で対象のゲームサーバーは予約済みになります。
- ゲームサーバーのアドレスとポートをクライアントに送信します。
- クライアントは受け取ったアドレス・ポートに接続し、通信を始めます。
- クライアントからの通信を確認したサーバープロセスは UpdateGameServer を呼び出し、自身が使用中になったことを GameLift FleetIQ に通知します。
- ゲームが終わったら DeregisterGameServer を呼び出し、ゲームサーバーの登録を解除します。
GameLift Hosting から GameLift FleetIQ に乗り換えて改善されたこと
改善点1: 1プロセスで複数のゲームを処理できるようになった
GameLift Hosting と違い、GameLift FleetIQ はゲームを実行する仕組みやデプロイ方法には関与しないため、自分たちで管理します。そのため、GameLift Hosting によるプロセスモデルの強制から解放され、1プロセスで複数のゲームを同時に処理できるようになりました。また、1インスタンスあたり50ゲームの制限があった GameLift Hosting に対して、 GameLift FleetIQ は負荷が許す限り1インスタンスにゲームを詰め込むことができます。現段階では、本プロジェクトは1インスタンス・1プロセスで同時に200ゲームを処理しています。
改善点2: 立ち上がりが早くなった
改善点1と同じくゲーム実行の仕組みやデプロイ方法を自分たちで管理できるようになったことで、言語や環境にあわせて最適なビルド・デプロイ手順を使えるようになりました。これによってデプロイ時間が30分から2分に短縮され、劇的にイテレーションが回しやすくなりました。
FlexMatch
これまで触れてきませんでしたが、GameLift に含まれるマッチング機能である FlexMatch も GameLift を使うモチベーションになります。マッチングはマルチプレイゲームが抱える大きな問題のひとつで、効率的に動作するコードを書くには相応の知識と慣れが必要です。FlexMatch は、マッチングのルールを JSON で記述すればあとはユーザー情報を放り込んでいくだけで勝手にマッチングしてくれます。マッチングのルールもかなり詳細に設定することができ「同じステージを選択していること」「キャラクターが重複しないこと」「合計戦闘力n以上」などさまざまな要素を組み合わせることができます。また、なかなかマッチングしないユーザーへの救済として時間経過とともにマッチングルールを変化させる機能もあり、FlexMatch を単独で使うという選択肢も十分にアリだと思いました。
/* 同じステージを選択していてキャラクターが重複しない3人がマッチングする定義 */
{
"name": "sample-matchmaking-rule",
"ruleLanguageVersion": "1.0",
"playerAttributes": [
{
"name": "StageId",
"type": "number"
},
{
"name": "CharacterId",
"type": "number"
}
],
"teams": [
{
"name": "party",
"maxPlayers": 3,
"minPlayers": 3,
"quantity": 1
}
],
"rules": [
{
"name": "StageId",
"type": "comparison",
"operation": "=",
"measurements": [ "flatten(teams[*].players.attributes[StageId])" ]
},
{
"name": "CharacterId",
"type": "comparison",
"operation": "!=",
"measurements": [ "flatten(teams[*].players.attributes[CharacterId])" ]
},
]
}
まとめ
GameLift Hosting は難しいインフラ知識がなくても始められるのが利点ですが、小回りが効かない印象でした。GameLift FleetIQ は利用者側にも知識が求められますがその分自由度が高く、インフラ担当者がいるような企業ではこちらを採用するほうがメリットが大きそうに思います。GameLift の今後のアップデートに期待しつつ、最適な活用方法を考えていきたいと思います。
この記事へのコメントはありません。