Amazon Web Services ブログ

Amazon GameLift と Amazon CloudWatch で実現するゲームサーバーのオブザーバビリティ

本投稿は、”Game Server Observability with Amazon GameLift and Amazon CloudWatch” を翻訳したものです。

ゲームサーバーを実行して、プレイヤー向けにセッションベースのゲームをグローバルにホストする場合、それらのゲームサーバープロセス内で何が起きているかを可能な限り可視化することが重要です。これには、メトリクスとログをリアルタイムで収集し、このデータに関する洞察を得て問題を調査し、パフォーマンス改善の機会を見つける機能が含まれます。

Amazon GameLift は、マルチプレイヤーゲーム用のクラウドサーバーをデプロイ、運用、スケーリングする、専用のゲームサーバーホスティングソリューションです。GameLift ホスティングを使用すると、ゲーム開発に集中できます。一方、GameLift はゲームサーバーのデプロイとスケーリング、およびゲームセッションの配置やマッチメイキングなどの他のタスクを管理します。GameLift は、フリート、キュー、ゲームセッション、プレイヤーセッション、マッチメイキングなどの GameLift リソースに関する豊富なメトリクスをネイティブに提供します。これらのメトリクスは、ゲームのパフォーマンスを視覚化する場合や、設定を改善してプレイヤーを効果的にマッチングさせ、適切な量のリソースを使用する場合に非常に役立ちます。CloudWatch で GameLift フリートを最適化する方法の詳細については、別のブログ記事があります。

ただし、これらのメトリクスに加えて、ゲームサーバーのプロセス内部の状態を可視化する必要があります。これを実現する一般的な方法としては、次の 3 つがあります。

  • リアルタイムにログを収集して効率的にクエリし、抽出結果をメトリクスやアラームの設定に役立てる
  • ゲームサーバーのプロセスレベルでリアルタイムメトリクスを収集する (CPU 使用率、メモリ使用量、ディスク読み取り/書き込みなど)
  • ゲームサーバープロセスからカスタムメトリクスを直接収集する (プレイヤーのアクション、接続の切断など)

このブログ投稿では、Amazon CloudWatch Agent を活用してこのデータをすべて収集し、CloudWatch でクエリを実行して視覚化する方法について説明します。GameLift ホスティングに重点を置いていますが、取り上げるトピックはすべて、EC2 ベースで自前で構築したゲームサーバーホスティングにも適用されます。

投稿全体を通して、GitHub のサンプルソリューションを参照します。このサンプルでは、Unity と C++ とのエンドツーエンドの GameLift 統合を紹介しています。また、前述のオブザーバビリティオプションもすべて実装されています。C++ ソリューションの詳細な概要については、このブログ投稿を参照してください。

GameLift 用に Amazon CloudWatch Agent をセットアップする

CloudWatch にカスタムログとメトリクスを送信できるようにするには、CloudWatch Agent をインストールして設定する必要があります。GameLift では、インストールスクリプトでこれを行います。Linux サーバーでは install.sh という名前になります。このソリューション例では、install.sh 内の CLI コマンドを使用してエージェントを設定する方法を示します。

#!/bin/bash

# Download and install the agent
wget https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
sudo rpm -U ./amazon-cloudwatch-agent.rpm

# Copy the cloudwatch agent configuration file to the right directory
sudo cp amazon-cloudwatch-agent.json /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json

# Start the agent
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s

設定の一部として、amazon-cloudwatch-agent.json という名前の別のファイルを参照していることがわかります。このファイルのさまざまな部分については、以下のさまざまなトピックで説明します。完全な設定は、サンプルの LinuxServerBuild フォルダーにあります。

Amazon GameLift 固有の重要な設定は、GameLift フリートの IAM ロールを定義する必要があり、このロールには CloudWatch Logs と CloudWatch メトリクスへのアクセス権が必要であるということです。作成した IAM ロールに CloudWatchAgentServerPolicy という管理ポリシーを割り当て、作成した GameLift フリートにこのロールを割り当てます。

インスタンスは GameLift サービスアカウントで実行されているため、この IAM ロールを引き受けるように CloudWatch Agent に個別に指示する必要があります。そのために、エージェント設定 json ファイルで以下のエージェント設定を定義します。

"agent": {
   "metrics_collection_interval": 10,
   "logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log",
   "credentials": {
       "role_arn": "arn:aws:iam::<YOURACCOUNT>:role/<YOURROLE>"
     }
   },

ご覧のとおり、エージェント出力ログファイルとメトリクスの収集間隔(秒)も定義しています。

CloudWatch Logs を使用したログの収集と検索

これでエージェントが完全に設定されたので、CloudWatch Logs に送信するログファイルを定義する必要があります。これは、設定ファイルの logs セクションを使用して実現できます。この例では、各 GameLift インスタンスで 2 つのゲームサーバープロセスを実行しており、どちらも独自のログファイルを作成します。これらのログファイルを独自のログストリームに送信するように設定するには、個別に定義する必要があります。これらと同じ出力ファイルをプロセス内部で構成します。この例では、ゲームサーバーのローカルタイムゾーンを使用していますが、ゲームサーバーのログを UTC に設定することもできます。

"logs": {
    "logs_collected": {
    "files": {
    "collect_list": [
   {
       "file_path": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log",
       "log_group_name": "AmazonCloudWatchAgentLogs",
       "log_stream_name": "AmazonCloudWatchAgentLogs-{instance_id}",
       "timezone": "UTC"
      },
      {
       "file_path": "/local/game/logs/myserver1935.log",
       "log_group_name": "GameServerLogs",
       "log_stream_name": "GameServerLogs-{instance_id}-1935",
       "timezone": "Local"
      },
      {
       "file_path": "/local/game/logs/myserver7777.log",
       "log_group_name": "GameServerLogs",
       "log_stream_name": "GameServerLogs-{instance_id}-7777",
       "timezone": "Local"
      }
    ]
   }
 },

ソリューションを起動して実行し、CloudWatch Log Groups に移動すると、GameServerLogs ロググループ内のすべてのゲームサーバープロセスの個別のログストリームが見つかります。

LogStreams

ゲームサーバーのプロセスメトリクスを収集する

次に、個々のゲームサーバープロセスすべてから個別にメトリクスを収集します。1 つの GameLift インスタンスで最大 50 個のゲームサーバープロセスを実行できるため、それらから個別にインサイトを取得すると、モニタリングとデバッグに大いに役立ちます。

CloudWatch Agent は、プロセスに対し procstat -metrics をサポートしています。これには、メモリ、CPU、ディスク使用量などの広範なメトリクスのサポートが含まれます。モニタリングするメトリクスを設定でき、必要なメトリクスを選択するだけで CloudWatch カスタムメトリクスのコストを管理できます。監視するプロセスを定義する必要があります。この例では、launchコマンドに基づいてフィルタリングすることでこれを行いました。今回の場合では、フィルタ値は “-port 1935” と “-port 7777” で、これらのポート設定が渡された2つのゲームサーバープロセスからのメトリクスが得られます。このフィルタを使用すると、プロセスを識別する DNS 名とポートを確認できるため、CloudWatch でも適切なディメンションが得られます。ゲームサーバープロセスは GameLift で sudo コマンドで実行されるため、この設定は sudo プロセスメトリクスを個別に追跡することに注意してください。以下に procstat 設定を示します。これは、設定ファイルのメトリクス設定内に配置されています。

"procstat": [
    {
     "pattern": "-port 1935",            
     "measurement": [
         "cpu_usage",
         "read_bytes",
         "write_bytes",
         "memory_rss"
     ]
   },
   {
       "pattern": "-port 7777",
       "measurement": [
           "cpu_usage",
           "read_bytes",
           "write_bytes",
           "memory_rss"
       ]
    }
 ]

ゲームサーバープロセスからカスタムメトリクスを収集する

プロセスレベルのメトリクスに加えて、ゲームに固有の、完全に自前のアプリケーションメトリクスを追跡したい場合がよくあります。これらのメトリクスはゲームサーバープロセス内部からのみ追跡でき、プレイヤーのアクション、ゲームセッションイベント、その他のゲーム固有のものなどを含みます。

CloudWatch Agent は、StatsD エージェントを通じてこれらのカスタムメトリクスをサポートします。StatsD は、アプリケーションレベルのメトリクスを収集するためのシンプルで軽量なデーモンです。UDP ポートでメトリクスイベントをリッスンし、ゲームサーバープロセスは任意の StatsD クライアントまたは自前の実装でイベントを送信します。これにより、ゲームサーバープロセスから送信されるメトリクスが切り離され、パフォーマンスへの影響が最小限に抑えられます。StatsD エージェントを設定するには、CloudWatch Agent 設定ファイルの “metrics “内に以下の設定を追加するだけで済みます。これは、リッスンしているポートと、集約と収集の間隔を定義しています。

"statsd":{
    "service_address":":8125",
    "metrics_collection_interval":60,
    "metrics_aggregation_interval":60
  },

サンプルソリューションでは、Unity サーバーに StatsD カスタムメトリクスが実装されています。このプロジェクトには、StatsD の tags-feature を使用してメトリクスを送信するシンプルなカスタム StatsD クライアントがあり、CloudWatch のディメンションにマッピングされます。これにより、特定のゲームセッションのメトリクスを特定できます。この実装は Assets/Scripts/Server/SimpleStatsdClient.cs にあります。独自の StatsD クライアントを実装したくない場合は、任意の既存の StatsD クライアントを使用しても構いません。

送信するサンプルメトリクスの一部では、カウンターとゲージの両方を使用しています。ゲージはメトリクスの正確な値を送信し、カウンターはメトリクスの合計値に加算されます。

ゲージの例として、接続しているゲームクライアントの数が挙げられます。

this.gamelift.GetStatsdClient().SendGauge("game.ClientSocketsConnected", this.clients.Count);

カウンターの例としては、ゲームセッションの開始があります。

this.statsdClient.SendCounter("game.SessionStarted", 1);

これらのメトリクスは、他のメトリクスと同様に CloudWatch で視覚化できます。これらは CloudWatch の CWAgent の下にあり、使用しているタグ/ディメンションに基づいて、hostgame session ごとにグループ化されています。タグを使用して、任意のディメンションを定義することもできます。

以下の画像は、1 つのゲームセッションで追跡されるサンプルカスタムメトリクスを示しています。プレイヤーのポジションの更新(比較的高い値)を追跡しているので、これがグラフ内で大きく表示されています。ただし、これを削除すると、他の指標により適した尺度が表示されます。

CustomMetrics

CloudWatch ダッシュボードでゲームサーバーのプロセスとカスタムメトリクスを視覚化

CloudWatch メトリクスはマネジメントコンソールからいつでも検索およびクエリできますが、これらのメトリクスに対してより永続的なビューを構築したい場合もあります。これは CloudWatch ダッシュボードで実現できます。CloudWatch ダッシュボードに任意のカスタムグラフを追加して、これらのビジュアライゼーションの設定を管理できます。機能の詳細については、ドキュメントを参照してください。

下図のダッシュボードでは、異なる場所でホストされている 2 つの GameLift フリートで追跡された CPU とメモリの使用状況を確認できます。また、ゲームセッションのプレイ時に、アイルランドフリートのプロセスの 1 つで CPU とメモリの使用量に対し小さなスパイクが発生していることも確認できます。ご覧のとおり、複数の AWS リージョンのメトリクスを単一のダッシュボードに追加して、世界中のゲームサーバー全体を一度に視覚化できます。

CWDashboard

結論

Amazon CloudWatch の機能を使用して、Amazon GameLift で実行されているゲームサーバープロセスに関する洞察を得る方法を示しました。同じツールと原則が、EC2 でホスティングしているすべてのカスタムゲームサーバーにも適用されます。ログとモニタリングデータに関するこれらの洞察は、ゲームサーバーの問題やボトルネックを特定し、それらのゲームサーバーのパフォーマンスを理解し、ゲームセッションの詳細やプレイヤーのアクティビティに関するビジネス上の洞察を得るのに役立ちます。

AWS は、オブザーバビリティのためのサービスのポートフォリオ全体を提供しています。Amazon OpenSearch Service, Amazon Managed Servuce for Prometheus, および Amazon Managed Service for Grafana などのサービスを使用して、モニタリング機能を拡張できます。また、Amazon Athena CloudWatch Connector を使用して Amazon Athena でメトリクスからインサイトをクエリし、Amazon QuickSight でそのデータをさらに視覚化することもできます。また、AWS パートナーが提供する、さまざまなサードパーティソリューションを利用することで、どのオブザーバビリティツールを選んでも対応できます。

翻訳はソリューションアーキテクトの安藤が担当しました。原文はこちらです。