Azure Container Instances (ACI) を使用する同期マルチプレイヤー

Premium 料金でホストされた仮想マシンを利用する、よりシンプルなアーキテクチャとメンテナンスがよければ、オンデマンドで自動的にスケーリングされ、使用 1 秒ごとに課金される、Azure Container Instances、Event Grid、Azure Functions を使用するこの代替ソリューションを調べてください。

サーバーの状態は、Azure Container Instances の外部で永続化する必要があります。

この記事では、GitHub のこのサンプルで使用されているアーキテクチャについて説明します。 このリファレンス アーキテクチャのコードはガイダンスの例にすぎず、運用環境で使用するにはコードの最適化が必要な場合があることに注意してください。

アーキテクチャの図

SAzure Container Instances を使用する同期マルチプレイヤー

関連するサービス

  • Azure Traffic Manager - 待機時間に基づいて、最も適したリージョンのゾーンにプレイヤーを接続するので、選択されています。
  • Azure Container Instances - Azure でコンテナーを実行するための最も高速で簡単な方法です。仮想マシンを管理する必要も、より高いレベルのサービスを導入する必要もありません。
  • Azure Functions - 小規模なロジックを実行するための最も簡単な方法として選択されています。
  • Azure Table Storage - コンテナー グループの状態を追跡するための簡単なキー/属性ストレージです。
  • Azure Event Grid - Azure サービスからのイベントに対するサポートが組み込まれているため選択されました。
  • Azure Blob Storage - 自動スケーリング ヘルパーの構成を格納するための場所だけが必要です。
  • リソース グループ - Azure Traffic Manager に対して 1 つのリソース グループを使用し、各リージョンのゲーム サーバー プールに対して 1 つのリソース グループを使用します (たとえば、北米に 1 つ、ヨーロッパに 1 つ、LATAM に 1 つ、アジアに 1 つなど)。

デプロイ テンプレート

プロジェクトを Azure サブスクリプションにデプロイするには、次のボタンをクリックします。

Deploy using an Azure Resource Manager template

この操作を実行すると、Azure サブスクリプションに対する azuredeploy.json ARM テンプレート ファイルのテンプレート デプロイがトリガーされ、必要な Azure リソースが作成され、このリポジトリからソース コードが取得されます。 これにより、Azure アカウントの料金が発生する場合があります。

Azure サービスの名前付け規則と制限事項をまとめた記事が含まれる一般的なガイドライン ドキュメントを参照してください。

プロジェクトをデプロイするためには、次の情報を指定する必要があります。

  • 場所: リソースをデプロイする Azure リージョンを選択します。 Azure Container Instances を利用できる場所を選択してください
  • 関数名: 関数アプリの一意の名前を選択します。 これにより関数の DNS が決定されるので、よく考えて選択してください。
  • リポジトリ URL: これにより、Azure 関数を作成するために取得するファイルが含まれるリポジトリが決まります。 既定のままにするか、独自のフォークに切り替えることができます。
  • ブランチ: これはプロジェクトの GitHub ブランチに対応します。

Azure Functions は無料の App Service プランでデプロイされるため、パフォーマンス向上のためにスケールアップが必要になる場合があります。

このプロジェクトでは、必要な Azure コンテナー インスタンスを作成/削除 /変更するために、Azure ARM API 管理サービスに対する認証を行うため、マネージド サービス ID およびその Azure Functions との関係を使用します。 デプロイ スクリプトにより関数アプリのアプリ ID が自動的に作成されますが、コンテナー インスタンスをホストするリソース グループに対するアクセス許可をこの ID に付与する必要があります。 そのためには以下を実行します。

  • Azure portal にアクセスします。
  • Azure コンテナー インスタンスを作成するリソース グループを見つけます (これは、関数アプリがホストされているのと同じリソース グループでもかまいません)。
  • [アクセス制御 (IAM)] を選択します。
  • ロールとして [追加][共同作成者] を選択し、関数アプリへのアクセスを割り当ててから、サブスクリプション/リソース グループのドロップダウン ボックスを変更して Azure 関数を選択します。
  • 終わったら、[保存] をクリックします。

さらに、デプロイが完了したらすぐに、こちらに記載されている手順を使用して、ACIMonitor 関数に対するイベント サブスクリプション Webhook を手動で追加する必要があります。 イベントを監視する適切なリソース グループを選択したことを確認します (つまり、コンテナーが作成される Azure リソース グループ)。 これにより、指定したリソース グループでリソースが変更されるとすぐに、イベント グリッドによって ACIMonitor 関数にメッセージを送信されるようになります。 これが終わると、デプロイできる状態になります。 必要に応じて、ACIMonitor 関数の URL を取得したらすぐに、この ARM テンプレートを使用してイベント グリッドのサブスクリプションをデプロイできます。

ポータルを使用してイベント グリッドのサブスクリプションをデプロイする場合、次の値を指定する必要があります。

  • 名前 - イベント グリッドのサブスクリプションの特徴的な名前を選択します。
  • トピックの種類 - [リソース グループ] を選択します (または、Azure コンテナー インスタンスをさまざまなリソース グループにデプロイする場合は [Azure サブスクリプション])。
  • サブスクリプション - Azure コンテナー インスタンスの作成を監視するサブスクリプション。
  • リソース グループ - 作成する Azure コンテナー インスタンスを含むリソース グループを選択します。 [すべてのイベントの種類を購読します] チェック ボックスがオンになっていることを確認します。
  • サブスクライバーの種類 - Webhook。
  • サブスクリプション エンドポイント - これには、ACIMonitor Azure 関数のトリガー URL が含まれます。
  • プレフィックス フィルター - 空白のままにします。
  • サフィックス フィルター - やはり空白のままにします。

最後に、Azure Functions の新しい v2 ランタイムでは、EventGrid バインド拡張機能の手動登録が必要になる場合があります。 通常の状況では、拡張機能は自動的にインストールされますが (extensions.csproj ファイルに登録されているため)、これが行われない場合は、手動で実行する方法について次の記事を確認してください。

ステップ バイ ステップの手順

  1. プレイヤーのクライアント デバイスは、トラフィック マネージャーに接続し、プレイヤーがゲーム サーバーを検索する要求をルーティングします。
  2. トラフィック マネージャーは、待機時間が最も短いリージョンのゾーンに接続し、マッチメイキングをポイントして、使用可能なゲーム サーバーを取得します。
  3. マッチメイキングは、ACIList Azure 関数を呼び出して、すべてのコンテナー グループからパブリック IP アドレスとアクティブなセッションの一覧を取得します。
  4. Azure 関数は、パブリック IP アドレス、アクティブなセッションの数、およびすべてのコンテナー グループからの状態が格納されている Azure Table Storage からテーブルを取得します。
  5. 使用できるものがない場合、ACICreate Azure 関数が呼び出されます。 コンテナーの状態は作成中です。
  6. ACICreate Azure 関数によってコンテナーが作成されます。
  7. コンテナーが作成または削除されたことをリッスンするため、イベント グリッドがフックされます。 しばらくすると (数分)、イベント グリッドは、作成されたコンテナーから関連するイベントを受け取ります。
  8. イベント グリッドは、イベント受信後に ACIMonitor Azure 関数を呼び出して、パブリック IP アドレスを渡すようにもセットアップされます。
  9. ACIMonitor Azure 関数は、新しく作成されたコンテナーからのパブリック IP アドレスを挿入し、コンテナーの状態を実行中に設定します。
  10. マッチメイキングは、プレイヤーの使用可能なサーバーを取得したので、詳細をクライアント デバイスに送信して、直接接続できるようにします。
  11. マッチメイキングは、ACISetSession Azure 関数を呼び出して、プレイヤーが割り当てられたコンテナーで実行されているアクティブなセッションの数を更新します。
  12. ACISetSession 関数は、Azure Table Storage を更新します。
  13. ある時点で、サーバーは不要になります。 プレイヤーがまだコンテナー インスタンスを使用している可能性があるため、コンテナーを手動で削除することはできません。強制終了する代わりに、ACISetState Azure 関数を呼び出して、コンテナーの状態を MarkedForDeletion に設定します。これにより、そのコンテナー インスタンスに対しては新しいプレイヤーがスケジュールされなくなります。
  14. ACISetState Azure 関数は、Azure Table Storage を更新します。
  15. ACIGC Azure 関数がときどき実行されて、MarkedForDeletion 状態のコンテナー インスタンスがすべて削除されます。
  16. ACIGC Azure 関数は、コンテナー インスタンスを実際に削除する ACIDelete Azure 関数を呼び出します。
  17. ACIDelete Azure 関数によってコンテナーが削除されます。

より具体的な使用例:

Azure コンテナー インスタンスのワークフロー

  1. 最初に、サーバー インスタンスはありません。
  2. プレイヤーが接続するために、サーバーが必要になります。 ACICreate が呼び出されます。
  3. 作成コマンドが実行されるとき、サーバーはまだ稼働していません。 状態は作成中です。
  4. デプロイが完了すると (数分)、ACIMonitor 経由のイベント グリッドで、サーバー インスタンス (コンテナー グループ 1) が特定の IP アドレス (つまり、1.2.3.4) で実行されていることが通知されます。 インスタンスの状態が実行中に更新されます。
  5. プレイヤーは、サーバー インスタンスに接続できるようになります。
  6. 別のサーバー インスタンスが必要になったものとします。 ACICreate を再び使用できます。または、スケールアウトしきい値を超過した場合は、代わりに ACIAutoScaler で ACICreate を使用して作成できます。
  7. 同じパターンで、新しいサーバーの準備ができていません。デプロイが完了すると、イベント グリッドは、ACIMonitor を使用して、サーバーが別の特定の IP アドレス (つまり、2.3.4.5) で実行されていることを通知します。 この 2 つ目のインスタンス (コンテナー グループ 2) の状態が実行中に更新されます。
  8. プレイヤーは、2 番目のインスタンスに接続できるようになります。
  9. 最終的に、ユーザーが決定したため、またはスケールインのしきい値を超えたため、2 番目のインスタンスは必要なくなります。 プレイヤーがまだ 2 番目のインスタンスを使用している可能性があるため、強制終了する代わりに、ACISetScale を呼び出して、サーバーを削除対象としてマークします。これにより、新しいプレイヤーは 2 番目のインスタンスにスケジュールされなくなります。 2 番目のインスタンスの状態は "MarkedForDeletion になります。
  10. プレイヤーが 2 番目のインスタンスでのプレイを終了すると、ガベージ コレクター ACIGB が実行され、ACIDelete をトリガーして、2 番目のインスタンスを完全に削除します。

スケーリング

ACIAutoScaler Azure 関数のセットアップは、環境変数を使用して構成できます (スケールイン/アウトのしきい値、最小/最大インスタンス数、クールダウン)。 自動スケーラーのロジックは次のとおりです。

  • 時間でトリガーされて 1 分ごとに実行され、既定では無効になっています。
  • 負荷は、接続されているプレイヤー数 / 合計プレイヤー容量です。
  • ("負荷" > 80% かつインスタンス数 < 最大) の場合は、ACICreate Azure 関数を呼び出して新しいインスタンスをスピンアップします。 これにより、スケールアウトが行われます。
  • ("負荷" < 60% かつインスタンス数 > 最小) の場合は、ACISetState Azure 関数を呼び出して、負荷が最小のインスタンスの状態を MarkedForDeletion に設定します。 これにより、スケールインが行われます。
  • スケールイン/アウトに対して、10 分のクールダウン期間があります。

Azure Container Instances のスケールアップは高速なので、数分で新しいコンテナーの準備できます。 たとえば、OpenArena を実行する新しい Azure コンテナー インスタンスを 30 個増やす要求は、要求が送信されてから、プレイヤーが接続できるようになるまで、3 分未満で済みます。

テスト用のコンテナー セットの手動作成

テストのために多数のコンテナー インスタンスを作成する場合は、こちらで入手できるサンプルを使用できます。 作成する各インスタンスで、openarenaserver1 を一意の名前に置き換えます (openarenaserver1、openarenaserver2、openarenaserver3 など)。 また、リソース グループ、場所、ストレージ名/キーも置き換えます。

その他のリソースとサンプル

詳細については、Build で録画された「Azure Container Instances を使用したマルチプレイヤー サーバーのスケーリング」セッションを参照してください。

価格設定

Azure サブスクリプションをお持ちでない場合は、無料アカウント を作成して 12 か月間の無料サービスの利用を開始できます。 それらのサービスの制限を超えない限り、Azure 無料アカウントで無償で提供されているサービスに対して料金が発生することはありません。 Azure Portal または使用状況ファイルを通じて使用状況を確認する方法について説明します。

これらのリファレンス アーキテクチャの実行中に使用される Azure サービスのコストはユーザーが負担し、その合計は分析パイプラインで実行されるイベントの数によって異なります。 リファレンス アーキテクチャで使用されていた各サービスの価格は、Web ページで確認ください。

また、Azure の料金計算ツールを使用して、使用する予定の Azure サービスのコストを構成および見積もることもできます。