Game Server  ホスティング on ECS/Fargate の紹介

こんにちは。こちらは [AWS for Games Advent Calendar 2022](https://qiita.com/advent-calendar/2022/aws-for-games) 18日目の記事です。

# TL;DR
Game Server を ECS/Fargate で実行する[ Github : aws-samples/fargate-game-servers](https://github.com/aws-samples/fargate-game-servers) を紹介します。想定読者は ECS/Fargate を使ってAPIサーバを実装した経験があり、今後、特に Dedicated Game Server を実装する予定があるエンジニア向けです。

# Game Server とは？
Game Server といっても範囲が広いため、今回は Dedicated Game Server をターゲットにした記事です。そもそも、Dedicated Game Server (DGS)とは何なのかご存じない方もいるかと思います。Dedicated Game Server とは、日本語だと**専用ゲームサーバ**や**リアルタイムサーバ**と呼ばれることもあります。
近年、コンソールゲームやモバイルゲームにおいて、オンラインマルチプレイを提供しているものは数多く存在しています。例えば、Dead by Daylight を思い浮かべていただければイメージしやすいのではないでしょうか。これらオンラインマルチプレイを実現するためには、プレイヤー同士の状態を相互にやり取りする必要があります。1つのやり方として Game Server を介しプレイヤー同士の状態を同期し合う方法があります。Game Server はその性質上リアルタイムな処理を要求されるため**ステートフル**なものが多くメモリ上でプレイヤーの状態を保持し、ゲームの状態を計算、同期する役割を担っています。

# なぜ ECS/Fargate なのか？
では、なぜ ECS/Fargate で Game Server をホスティングしようと試みるのでしょうか？
それは既に多くのゲーム開発現場でバックエンドサービス（API）が ECS/Fargate で構築されているからです。 ECS/Fargate で得たノウハウを Game Server で活用する流れは自然かと思います。また、 ECS/Fargate はゲーム開発者からは圧倒的なメンテナンスコストの低さに定評があります。もちろん ECS/Fargate ですべてが解決できるわけではありませんし、独自で実装が必要な部分もあります。 他にも Game Server を想定した Agones や GameLift といったサービスもありますが、それぞれの学習コストかかるのも事実です。ただ、これらは開発/運用負荷が軽減されるといったメリットも当然あるでしょう。技術選定はそれぞれの pros/cons を踏まえて選択する必要があります。

# 具体的にはどういうものなの？
とは言え、今回は ECS/Fargate で Game Server をホスティングするってどういうものなのかをご紹介します。今回、紹介するのは ECS Task で Game Server を実行する方法です。特に ECS Task に Fargate のコンピュートを利用することで EC2 で運用していたインスタンスのメンテナンスから開放されます。 また、 ECS Task は Gobal IP(GIP) と Port を割り当てられるので、クライアントに Game Server の接続先の GIP と Port を提供し、接続することで Game Server として利用できます。
![gds.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210/b6657bc7-8276-a1f0-0e52-95d7795ccb79.png)
上記は一つのサンプルです。①プレイヤーは API サーバへ「対戦」をリクエストします。API サーバの処理は割愛しますが、ゲームセッションの管理や対戦相手のマッチングを行います。②API サーバで諸々の情報が計算され、プレイヤーに「対戦場所」となる Game Server の IP と Port を返します。③プレイヤーは Game Server に TCP/UDP で接続しゲームでの対戦を行います。


# サンプルプロジェクトの紹介
今回は AWS Blog の記事の [Game Server Hosting on AWS Fargate](https://aws.amazon.com/jp/blogs/gametech/game-server-hosting-on-aws-fargate/) を紹介します。 Github リポジトリは[こちら](https://github.com/aws-samples/fargate-game-servers)。 こちらは ECS/Fargate で Game Server をホスティングするプロジェクトとなっており、簡単なゲームセッション管理とユーザ配置、スケーリング機能実装がサンプルとして実装されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210/6ad81d32-474a-8712-36fe-e326a50a12fe.png)

## プレイヤーが Game Server へ接続するまでの流れ
このプロジェクトを理解するために、プレイヤーが「対戦」するまでの流れを見ていきましょう。
1. Cognito で認証
1. プレイヤーが `API Gateway` へ対戦をリクエスト
1. `API Gateway` から `Lambda` が Invoke されゲームセッション情報（ルームやロビー）を管理する `Redis` の中を検索
    - ゲームセッションがあれば、割り当てられた IP と Port をレスポンスとして返す
    - セッションがなければ、新しくゲームセッションを作成し IP と Port をレスポンスとして返す
    - （通常であれば、マッチングログジックはもっと複雑）
1. プレイヤーは `API Gateway` から受け取った IP と Port を元に `ECS/Fargate` でホストされている Game Server へ接続
1. 人数が揃い次第、対戦開始！！
1. 最後、対戦が終わったら Game Server から切断

## バックエンドの紹介
ここまで、プレイヤー視点で Game Server に接続する所まで追いかけてきました。次はそのバックエンドで何が構成されているのか見ていきましょう。


### ゲームセッション管理 / ユーザ配置
APIサーバはプレイヤーから対戦のリクエスが来た際にゲームセッションの作成や割り当てを処理する必要があります。サンプルプロジェクトではゲームセッションの作成や割り当てやマッチングについては深く実装されておらず、リクエストが来た順番に作成と割り当てを行うレベルです。また、ゲームセッション情報は共有する必要があるため Redis で保存・管理しています。最後に、対戦が終わった場合はゲームセッションを破棄する必要があります。ゲームセッションの破棄は Game Server から定期的に対戦の状況が Lambda を通じて Redis へ更新される仕組みになっています。 

### Fargate と ECS Task とコンテナの関係
![dgs2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210/c2e14f38-5c9d-2959-bae9-0a762188586d.png)
ECS では動的なコンテナ割当は出来ないので注意が必要です。今回のサンプルプロジェクトでは、1Fargate に10個のコンテナを稼働させるようにし、それぞれのコンテナで Game Server を動かしています。実際にECSで Game Server を実装する際には、 Game Server のリソースを計算し ECS Task Definition にいくつコンテナを割り当てられるのかは事前に計算し定義しておく必要があります。

### Game Server のスケール管理
なぜ Game Server をスケールさせる必要があるのでしょうか？ 今回のサンプルプロジェクトでは１Fargate あたり10個のコンテナが動作します。つまり、１Fargateしか動かしていなければ、対戦場所（ルーム）という意味では１０ゲームセッションしかありません。やはり多くのプレイヤーに遊んでもらうために Game Server のスケールは欠かせないと言えます。ただ、常に使われない程の余剰なリソースを動かし続けていてもコストに跳ね返ってきます。理想はユーザのリクエストと同等のゲームセッションが立ち上がることです。常にリクエストと同等のゲームセッションを即座に立ち上げるのは、サンプルプロジェクトでは難しいですが、ある程度余裕を持った状態でゲームセッションを作るのは可能です。中の実装としては毎分 Lambda が実行され、ゲームセッションを管理する Redis からキャパシティを確認し、逼迫した状態であれば ECS Task を立ち上げて、 Ready 状態のゲームセッションを作成します。残念ながら、サンプルプロジェクトではスケールインの実装はありませんが、 [scaler.py](https://github.com/aws-samples/fargate-game-servers/blob/master/BackendServices/functions/scaler.py) を拡張することで実現できます。

# 最後に
Dedicated Game Server を ECS/Fargate で実行する[ Github : aws-samples/fargate-game-servers](https://github.com/aws-samples/fargate-game-servers) を紹介しました。あえて言いますが、今回紹介した技術がすべてのオンラインマルチプレイのゲームに当てはまるわけではありません。オンラインゲームも多様化してきており、ニーズに合わせたアーキテクチャーや技術の選定が必要になってきています。本投稿ではその一つの選択肢として ECS/Fargate で Game Server をホスティングする際の技術や考え方について紹介させていただきました。少しでも参考になれば嬉しいです。

(免責) 本記事の内容はあくまでも個人の意見であり、所属する企業や団体は関係ございません。