Legendsなど成功している多くのビデオゲームでは、プレイヤーがゲームの一部に無料でアクセスできる”Free-to-Play”モデルを採用しています。このようなゲームは、もはや低品質なものではなく、プレミアムな品質を必要とします。スポットインスタンスは実行可能な低コストのコンピューティングオプションを提供します。EKSコンテナのオーケストレーションではプレイヤーへの影響を最小限に抑え、コストを最適化するメカニズムが必要となりますが、そのような場合にはスポットインスタンスの利用がフィットします。スポットインスタンスはAWSクラウドの利用可能な予備のコンピュートキャパシティを提供することで、オンデマンドに比べて大幅な割引価格でご利用が可能です。スポットインスタンスによるコストを最適化によって、これまでと同じ予算でアプリーケーションのスループットを最大10倍にまでスケールできます。スポットインスタンスはフォールトトレラント(障害許容)なワークロードに最適です。マルチプレイヤーゲームサーバも例外ではありません。ゲームサーバの状態は、リアルタイムなプレイヤーの入力によって更新され、サーバは一時的な状態を保持します。ゲームサーバのワークロードは使い捨てになることが多く、スポットインスタンスを利用することでコンピュートにかかるコストを最大90%削減できます。このブログでは、スポットインスタンスを効果的に使用するためのゲームサーバワークロードの設計方法について説明します。簡単に言えば、マルチプレイヤーゲームサーバは現在のキャラクターの位置と状態(主にアニメーション)を更新するためにほとんどの時間を費やします。残りの時間は、戦闘に関するアクションや移動、その他ゲームイベントに関連する画像の更新に費やされます。具体的にゲームサーバのCPUは、クライアントの位置情報を受信し、ゲームステートを計算し、その情報を特定の複数のクライアントに送信するという処理のためにネットワークI/Oを利用します。以上のことから、ゲームサーバのワークロードはカジュアルなマルチプレイヤーゲームには汎用インスタンスタイプ、ハードコアなマルチプレイヤーゲームにはコンピューティング最適化インスタンスタイプが適しています。AWSはコンピューティング最適化(C4およびC5)や汎用(M5)をはじめとした多種多様なインスタンスタイプにおいてスポットインスタンスを提供しています。キャパシティはアベイラビリティゾーン内のインスタンスタイプごとに別々に変動するため、幅広いインスタンスタイプを使用することで同じ価格でより多くのコンピューティング能力を得ることができます。Instancesの開始方法をご覧ください。GameLiftがあります。FleetIQやスポットインスタンスをデプロイします。Rate)をベースとして新しいセッションをゲームサーバに振り分けます。Instances“をご覧ください。(※)スポットインスタンスは空きリソースを提供している特性上、インスタンス需要に応じて中断されることがあります。詳しくはスポットインスタンスの中断をご覧ください。ECSなどのコンテナベースのオーケストレーションによるゲームサーバのデプロイメントパターンを利用することができます。これらのシステムは大量のゲームサーバとしてデプロイされた複数のリージョンにまたがるDockerコンテナを管理します。本ブログの残りのパートではコンテナ化されたゲームサーバソリューションにフォーカスします。コンテナは軽量で、高速に起動し、ベースとなるインスタンスの使用率が向上するという特性があるため、ゲームサーバのワークロードに適しています。スポットインスタンスを利用するのか?スポットインスタンスは、使い捨てのゲームサーバワークロードを実行するための選択肢のひとつです。中断2分前に通知を受け取ることで、中断に備えることができます。CloudWatchによる通知処理の例を2つご紹介します。詳しくはこのブログの後半の「中断のハンドリング」および「ゲームサーバを冗長化するためには?」を参照してください。スポットインスタンスは汎用およびコンピューティング最適化(C4およびC5)などゲームサーバのワークロードに適合するさまざまなEC2インスタンスタイプを提供します。スポットインスタンスは低い中断レートを提供します。スポットインスタンスアドバイザーは過去の履歴に基づいて、中断レートの低いインスタンスタイプを選択するのに役立ちます。中断のハンドリングスポットインスタンスを使用する場合、中断によるプレイヤーへの影響を回避することが重要です。Server“で公開されているリファレンスアーキテクチャとサンプルコードによって、プレイヤー影響を避けるための戦略についてご紹介します。Drainageを例として挙げます。これにより、ノードのアンスケジューリング(解除)が可能となり、プレイヤーエクスペリエンスに影響を及ぼす可能性がある終了期間(terminationGracePeriodSeconds)にあるノード上で実行されているpodを削除します。その結果、podは正常に終了するシグナルがゲーム内に送信されている間も可動を続けます。CloudWatchまたはインスタンスメタデータからスポットインスタンスの中断に関する情報を取得するためにDaemonSetとして実行されるエージェントpodが必要です。今回はインスタンスメタデータによる通知を利用します。Drainageによる終了イベントのハンドリングに関する説明です。GitHub上のYAMLファイルのデプロイ例もご参考ください。“terminationGracePeriodSeconds”のデフォルトを120秒としてゲームサーバpodを起動します。GitHub上のYAMLファイルもご参考ください。Poolをプロビジョニングします。こちらのポリシーは最低価格によるスポットインスタンスのアロケーション戦略を利用します。CloudFormationテンプレートをご参考ください。tool(推奨AMI中の/etc/eks/bootstrap.sh)を利用します。–node-labels=lifecycle=spot,title=minecraft,region=uswest2”すべてのノードにデプロイされたDaemonSetはインスタンスメタデータのエンドポイントから終了ステータスを取得します。node’コマンドが実行され、ゲームサーバpodに対してSIGTERMのシグナルが送信されます。file“をご覧ください。ゲームサーバはその後120秒間実行され、ゲームはプレイヤーに対し終了通知を受け取ったことを通知することができます。“unschedulable”にマークされたノードには新しいゲームサーバはスケジュールされません。マッチメイキングシステムなどの外部システムに対する通知が送信され、利用可能なゲームサーバのインベントリ情報が更新されます。Node上でゲームサーバの最適な配置に関する、kubernetesの仕様で推奨される戦略をいくつかご紹介します。Nodeとして使用します。Scalingグループ内のノード上でゲームサーバのスケジューリングを制御します。CloudFormationテンプレートによって設定されます。StringプレイヤーからのアクションがUDPによって提供されていて、かつプレイヤーに対してインスタンスの中断を見せない必要があるケースがあるかもしれません。今回はゲームサーバアロケータ(今回はKubernetesスケジューラ)が、UDPロードバランサの背後にいるゲームサーバをアップストリームターゲットとしてスケジュールします。スケジューラがノード終了時にゲームサーバを終了する際はフェールオーバーがシームレスに行われます。詳しくは本ブログ後半の「ゲームサーバを冗長化するには?」をご参照ください。EKSにおけるオンデマンド/スポットインスタンスを混在させたマルチプレイヤーゲームサーバのアーキテクチャを表しています。単一のVPC内では、コントロールプレーンノードプール(マスターホストとストレージホスト)には高可用性が求められるため、オンデマンドインスタンスを利用しています。ゲームサーバのホスト/ノードはスポットとオンデマンドインスタンスを混在させて利用します。Balancerを介してアクセスが可能です。ゲームサーバを冗長化するためには?ゲームサーバはステートフルなワークロードのため、従来は冗長性の無い単一の専用ゲームサーバインスタンスとして実行されます。Balancerを提供しています。EKSのpodとしてデプロイされたゲームサーバを冗長化するためのソリューションを提案します。スポットインスタンスをUDPロードバランサとして利用していますが、必ずスポットインスタンスである必要はありません。EKS上でUDPロードバランサを実装するためのリファレンスアーキテクチャとなります。EKSクラスターのセットが必要です。現在稼働中のゲームサーバのステータスや配置を収集するゲームサーバのインベントリなどが該当します。DynamoDBのテーブル内に永続化されます。プレイヤーの割当が必要な場合、マッチメイキングサービスはDynamoDBテーブルを使用するゲームサーバインベントリのAPIエンドポイントに対してプレイヤーに最適なサーバを照会します。本ソリューションは以下のメインとなるコンポーネントを含んでいます。ゲームサーバ(GitHub上のmockup-udp-serverを参照)。こちらは接続されたプレイヤーからゲームの状態の差分を受け取り、疑似計算を元に更新された状態を他のプレイヤーに送信するシンプルなUDPソケットサーバです。こちらは専用ゲームサーバでUDPベースのロードバランシングのシュミレーションを目的としたシングルスレッドサーバです。true”が設定されたKubernetesのpodであり、単一のコンテナとしてデプロイされます。ロードバランサ(udp-lb)。こちらはコンテナ化されたストリームモジュールをロードしたNGINXサーバです。ロードバランサのアップストリームセットはDynamoDBテーブル(game-server-status-by-endpoint)上の専用ゲームサーバのステータスをベースに初期化時に設定されます。利用可能なロードバランサインスタンスもマッチメイキングなどのコアゲームサービスから利用されるためにDynamoDB(lb-status-by-endpoint)に保存されています。ゲームサーバとロードバランサのインベントリに関するクラスタの状態を保持するDynamoDBテーブル。Lambda(game-server-inventory-api-lambda)をベースとしたAPI。本APIはロードバランサの設定に必要なアップストリームターゲットとなるゲームサーバを設定するために”/get-available-gs”というオペレーションをサポートする。利用可能なゲームサーバインベントリからすでに要求されているゲームサーバにラベルを付与するための”/set-gs-busy/{endpoint}”もサポート。SQSをトリガとし、DynamoDBテーブルへデータを保存するLambdaファンクション(game-server-status-poller-lambda)スケジューリングのメカニズム同じロードバランサにあるゲームエンドポイントが同時に中断される可能性を低減する必要があります。したがって、同じホスト上におけるゲームサーバのスケジューリングを防止しなくてはいけません。Kubernetes“を利用します。次のように、podAffinityセクションでmockup-grp1とmockup-grp2の2つのラベルを定義します。"kubernetes.io/hostname"“requiredDuringSchedulingIgnoredDuringExecution”はpodのスケジューリング時に後続のルールを満たす必要があることをスケジューラに伝えます。mockup-grp-2と同じノードにスケジューリングされません。ロードバランサのpod(udp-lb)がスケジューリングされると、異なるノードで稼働する2つのゲームサーバpodが稼働しているかの確認についてgame-server-inventory-apiエンドポイントに対して照会されます。このリクエストの条件が満たされない場合、利用可能な2つのゲームサーバの準備が整うまでロードバランサpodはクラッシュループに陥ります。EKSクラスタを構築する方法について2つの例をご紹介しました。Serverは、クラスタを作成、スポットインスタンスとコンテナ化されたゲームサーバをデプロイします。Glutamateでは、ゲームサーバのワークロードを強化し、スポットインスタンスの中断を処理するためのメカニズムとしてゲームサーバの冗長性を実現しました。まとめマルチプレイヤーゲームサーバは数分から数時間の間で持続する短命なプロセスで実装されています。USおよびEUリージョンで現在観測されているスポットインスタンスの平均稼働時間は数時間から数日の間であることから、スポットインスタンスはゲームサーバのワークロードに適していると言えます。EKSはプレイヤーエクスペリエンスを中断する可能性を最小限に抑えるメカニズムを備えています。これらにより、スポットインスタンスはカジュアルなマルチプレイヤーゲームサーバだけでなく、ハードコアゲームサーバにとっても魅力的なオプションとなります。マルチプレイヤーゲームサーバにスポットインスタンスを使用するゲームスタジオでは、コンピューティングコストを最大90%節約しており、彼らだけでなくプレイヤーにとってもメリットがあります。ゲームサーバにスポットインスタンスをご活用ください。Cowanの寄稿です。がい、年齢、その他の属性によって差別することなく、平等に採用選考の機会を提供しています。