サーバーレスでできるリアルタイム通信 !  

AWS AppSync Events を使ってゲームギルドチャットを作ってみよう

2025-04-02
デベロッパーのためのクラウド活用方法

Author : 大西 啓太郎、西坂 信哉

オンラインゲームにおいて、ギルドチャットは欠かせないコミュニケーション機能です。プレイヤー同士が協力してボスを倒したり、戦略を練ったり、単に雑談を楽しんだりする場として重要な役割を果たしています。

従来のギルドチャットシステムは、WebSocket サーバーやカスタムメッセージングサーバーを構築・運用する必要があり、開発や運用の負担が大きいものでした。しかし、2024 年 10 月に発表された AWS AppSync Events を活用することで、サーバーレス WebSocket API によるスケーラブルなギルドチャットシステムを簡単に実装できるようになりました。

この記事では、AWS AppSync Events を使用して、WebSocket インフラの構築やコネクション状態の管理、ファンアウトの実装を気にすることなく、メンテナンスが容易でコスト効率の高いゲーム内ギルドチャットを実装する方法をご紹介します。

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. AWS AppSync Eventsとは ?

AWS AppSync Events は、2024 年 10 月に発表された AWS AppSync の新機能です。AppSync というと「GraphQL のマネージドサービス」というイメージが強いかもしれませんが、実は今回のアップデートは GraphQL は関係ありません。

従来、リアルタイム通信を実現するためには、WebSocket サーバーの構築・運用、コネクション状態の管理、メッセージのファンアウト実装など、多くの技術的課題がありました。AWS AppSync Events はこれらの課題を解決し、安全で高性能なサーバーレス WebSocket API を提供します。

この機能の核心は、チャネルベースの Pub/Sub モデルにあります。開発者はチャネル名前空間を定義し、その中に様々なチャネルを動的に作成できます。クライアントは特定のチャネルをサブスクライブし、サーバーサイドのコードは簡単な HTTP リクエストでイベントをパブリッシュできます。ワイルドカード機能を使えば、複数のチャネルを一度にサブスクライブすることも可能です。

AWS AppSync Events の最大の特長は、インフラ管理からの解放です。WebSocket コネクションの確立・維持、認証、スケーリングといった煩雑な作業を AWS が全て処理するため、開発者はビジネスロジックに集中できます。数人から数百万人のユーザーまで、自動的にスケールするため、トラフィック変動の心配もありません。AWS AppSync Events API はサーバーレスで、使用した分だけ支払うため、コスト効率も優れています。


2. アーキテクチャ概要

今回実装するギルドチャットシステムのアーキテクチャは以下のとおりです。

主なコンポーネントは以下の通りです。

フロントエンド

  • Webブラウザ (HTML/JavaScript) : 今回のサンプル実装では Web ブラウザベースの UI を使用します。この HTML とJavaScriptは、AWS App Runner 上の Express.js サーバーから直接配信されます。
  • ゲームクライアント (Unity、Unreal Engine など) : 同じバックエンド API を利用して、ネイティブゲームクライアントからも接続可能です。

バックエンド

  • AWS App Runner 上の Express.js サーバー: RESTful API による、ギルド管理、メッセージ履歴管理、JWT 認証、といった機能と、フロントエンドの配信機能を担当します。
  • AWS AppSync Events: WebSocket 接続管理を含めた、リアルタイムメッセージング部分の機能を担当します。
  • AWS Lambda: AppSync Events の認証処理を行うハンドラーとしての機能を担当します。


主な処理フローは以下の通りです。

認証フロー
本サンプルでは、チャンネルへの接続 (Connect) およびメッセージの送信 (Publish) には API キーによる認証を、メッセージの受信 (Subscribe) では RS256 アルゴリズムを使用した JWT ベースの認証を使用します。JWT ベース認証のフローは以下の通りです。

  1. App Runner上のバックエンドサーバーが認証処理の後、JWT を発行
  2. クライアントが JWT を Authentication ヘッダーに格納し、AppSync Events へ Subscribe 要求を送信
  3. Lambda 関数が JWT を検証し、Subscribe をリクエストされたチャネルにアクセスする権限があるかどうか確認
  4. 権限があればアクセス許可、なければアクセス拒否として応答

※ なお本記事執筆時点では、認証方式として「API キー」「Lambda 認証」「HAQM Cognito ユーザープール」「AWS Identity and Access Management (IAM) 認証」「OpenID Connect」が選択できます。本番利用においては適切な認証方式の選定・利用をご検討ください。

通信フロー

  • メッセージ送信 (Publish): クライアントがメッセージを RESTful API 経由で App Runner 上のバックエンドサーバーへ送信します。バックエンドサーバーは AppSync Events に HTTP 経由でメッセージを Publish します。
  • メッセージ受信 (Subscribe): クライアントが AppSync Events の Websocket に接続することで、リアルタイムにメッセージを受信します。

なお 2025 年 3 月 13 日のアップデート で、WebSocket 接続経由でのメッセージ publish も行えるようになりました。HTTP 経由の publish と比較すると、実装がシンプルになったり、publish の通信オーバーヘッドが減ることによるレイテンシー低減などの効果が見込めます。一方で、本サンプルのように API サーバーを介した HTTP 経由の publish では、高度なメッセージモデレーションやログ取得機能を持たせやすいメリットもあります。例えばゲームチャットでは、NG ワードフィルタリングをしたいので HTTP 経由とするが、ステータス同期はレイテンシー低減のため WebSocket 経由とするなど、用途によって適した方法を選択できます。


3. AWS AppSync Event API の実装

3-1. AWS AppSync Event API の作成

まず、AWS Management Console で AWS AppSync Events の設定を行います。

AWS AppSync コンソールにアクセスします。

クリックすると拡大します

Event API を作成」を選択します。

クリックすると拡大します

API に名前を付け (例: GuildChatAPI)、「作成」を選択します。

数秒で API が作成され、イベント API、デフォルトの名前空間、API キーが自動的に生成されます。

クリックすると拡大します

設定」タブを選択し、「認可モード - API キー」、「DNS エンドポイント - HTTP」 および「DNS エンドポイント - リアルタイム」が発行されていることを確認し、コピーしてメモに控えておいてください。

クリックすると拡大します

3-2. AWS Lambda 認証ハンドラーの実装

AppSync Events の認証を行うための Lambda 関数を作成します。この関数は JWT トークンを検証し、ユーザーが適切なギルドチャネルにのみアクセスできるようにします。

実際のゲーム環境では、ギルドに所属していないプレイヤーが悪意を持ってチャットに参加することを防ぐ必要があります。Lambda 認証を使うことで、ゲームバックエンドが発行した正規の JWT トークンを検証し、各プレイヤーが自分の所属ギルドのチャネルにのみアクセスできるようにセキュリティを確保できます。

また、ほとんどのゲームでは、ログイン、キャラクター情報、アイテム管理などですでに認証されたセッション情報を持っているため、その既存の認証基盤と連携したセキュリティモデルが自然です。Lambda 認証ハンドラーを用いることで連携を容易にします。

AWS Lambda コンソールにアクセスします。

クリックすると拡大します

関数を作成」を選択します。

クリックすると拡大します

  • 「関数名」: 「guild-chat-auth-handler
  • ランタイム : 「Python 3.12」

※ 最新の選択できるランタイムバージョンとは異なりますが、後述の AWS CloudShell の Python とバージョンを揃える為、「Python 3.12」を選択することを強く推奨します。

他はデフォルトの設定で「関数の作成」を選択します。

クリックすると拡大します

AWS CloudShell にアクセスします。AWS CLI を使用してZIP ファイルを Lambda 関数にデプロイするにあたり、このAWS CloudShell 上のシェルでコマンド操作を行います。

クリックすると拡大します

AWS CloudShell を使用して、サンプルプロジェクトの ZIP ファイルから Lambda 関数に必要なパッケージとソースコードををデプロイします。

# ZIPファイルをダウンロード
curl -L http://pages.awscloud.com/rs/112-TZM-766/images/appsync-event-api-demo-lambda.zip -o lambda.zip

# ファイルを解凍
unzip lambda.zip

# 解凍したディレクトリに移動
cd appsync-event-api-demo-lambda

# Python 3.12のバージョンに切り替え
sudo yum -y install python3.12
sudo ln -sf /usr/bin/python3.12 /usr/bin/python3
python3 -m ensurepip --upgrade

# requirements.txt を元にパッケージをインストール (Linux 環境向けのビルド済みバイナリを使用します)
pip install \
  --platform manylinux2014_x86_64 \
  --implementation cp \
  --only-binary=:all: --upgrade \
  --target=./package \
  -r requirements.txt

# イベントハンドラー関数を含めたZIPファイルの作成
cd package
cp ../lambda_function.py .
rm ../lambda.zip
zip -r ../lambda.zip .

# AWS Lambdaへのデプロイ
aws lambda update-function-code \
  --function-name guild-chat-auth-handler \
  --zip-file fileb://../lambda.zip

この認証ハンドラーの主なポイントは以下の通りです:

  1. JWKS エンドポイント連携: バックエンドサーバー (Express.js) が提供する JWKS (JSON Web Key Set) エンドポイントから公開鍵を取得して JWT を検証します。これにより、署名鍵の管理が簡単になります。
  2. チャネル名とギルド名の検証: トークンのペイロードに含まれる guildname と、アクセスしようとしているチャネル名が一致するかを検証します。これにより、プレイヤーは自分が所属するギルドのチャットにのみアクセスできます。
  3. 堅牢なエラーハンドリング: 無効なトークンや不正なチャネルアクセスをきちんと拒否し、セキュリティを確保します。

※ 本番利用に向けては、要件に応じた適切な JWT 検証処理の実装をご検討ください。

3-3. Lambda 認証を使用するためのチャネル名前空間の設定

作成した Lambda 関数を AppSync Events の認証ハンドラーとして設定します。

「AWS App Sync」で作成した、「GuildChatAPI」の「設定」タブから、「認可設定」にある「追加」を選択します。

クリックすると拡大します

  • 「認可モード」:「AWS Lambda」
  • 「AWS リージョン」: 「AP-NORTHEAST-1」
  • 「関数の ARN」: 「guild-chat-auth-handler

を選択し、「追加」を選択します。

クリックすると拡大します

続いて、作成した Lambda 関数をサブスクライブ認証に使用する名前空間を作成します。

「AWS App Sync」で作成した、「GuildChatAPI」の「名前空間」から、「名前空間を作成」を選択します。

クリックすると拡大します

  • 「名前空間名」: 「guild」
  • 「この名前空間にカスタム認証を追加」: チェックを入れる
  • 「認証モードをパブリッシュ - オプション」: 「API_KEY」
  • 「サブスクライブ認証モード - オプション」: 「AWS_LAMBDA」

を選択し、「作成」を選択します。

※ 「default」名前空間は今回は不要のため、セキュリティ考慮する場合は削除してください。残したままでも後続の手順は進められます。

クリックすると拡大します


4. バックエンドサーバーの実装

バックエンドサーバーは、Node.js と Express.js を使用して実装します。今回はコンテナアプリケーションを手軽にホスティングできる AWS App Runner を利用します。
このサーバーは以下の重要な機能を提供します:

  • ギルドとメンバーの管理
  • Web アプリケーション UI (HTML/CSS/JavaScript) の提供
  • JWT 発行と JWKS エンドポイントの提供
  • メッセージの AppSync Events への転送

AWS CloudShell にアクセスします。しばらくはこの AWS CloudShell 上のシェルでコマンド操作を行います。

クリックすると拡大します

4-1. AWS CloudShell でサンプルコードを準備

AWS CloudShell を使用して、サンプルプロジェクトの ZIP ファイルからサーバーをデプロイします。

# 作業ディレクトリへ移動 
cd ~

# ZIPファイルをダウンロード
curl -L http://pages.awscloud.com/rs/112-TZM-766/images/appsync-event-api-demo-guild-chat.zip -o guild-chat.zip

# ファイルを解凍
unzip guild-chat.zip

# 解凍したディレクトリに移動
cd appsync-event-api-demo-guild-chat

# ファイル内容を確認
ls -la

ZIP ファイルには、完全に機能するギルドチャットサーバーのすべてのファイル (Dockerfile、package.jsonindex.js など) が含まれています。

4-2. HAQM Elastic Container Registry (ECR) リポジトリの作成と Docker イメージのビルド・プッシュ

ECR リポジトリの作成から Docker イメージのビルド・プッシュまで、すべて CloudShell で行います。

# リージョンを設定
export AWS_REGION=ap-northeast-1

# ECR リポジトリを作成
aws ecr create-repository --repository-name guild-chat-server

# 作成されたリポジトリの URI を取得
export ECR_REPOSITORY_URI=$(aws ecr describe-repositories --repository-names guild-chat-server --query 'repositories[0].repositoryUri' --output text)
echo "リポジトリURI: $ECR_REPOSITORY_URI"

# ECR にログイン
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REPOSITORY_URI

# Docker イメージをビルド
docker build -t guild-chat-server .

# イメージにタグを付ける
docker tag guild-chat-server:latest $ECR_REPOSITORY_URI:latest

# イメージを ECR にプッシュ
docker push $ECR_REPOSITORY_URI:latest

# イメージの URI
echo $ECR_REPOSITORY_URI:latest

4-3. JWT 認証に用いる公開鍵・秘密鍵の作成

JWT 認証には公開鍵・秘密鍵のペアが必要となるため、以下の手順にて、openssl を用いて鍵を作成します。ここで出力した各鍵の値は後の手順で利用するため控えておいてください。

# JWT トークンの署名に用いるキーペアの作成
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private.pem -out public.pem

# Base64 エンコード
export JWT_PRIVATE_KEY_BASE64=$(cat private.pem | base64 -w 0)
export JWT_PUBLIC_KEY_BASE64=$(cat public.pem | base64 -w 0)

# JWT_PRIVATE_KEY_BASE64 (秘密鍵)
echo $JWT_PRIVATE_KEY_BASE64

# JWT_PUBLIC_KEY_BASE64 (公開鍵)
echo $JWT_PUBLIC_KEY_BASE64

4-4. AWS App Runner の設定

次に、ECR イメージを使用して AWS App Runner サービスを作成します。

AWS App Runner にアクセスします。

クリックすると拡大します

サービスの作成」を選択します。

クリックすると拡大します

  • 「コンテナイメージの URL」:「xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/guild-chat-server:latest」※ 前章で ECR にプッシュしたイメージの URI (:latest 含む) を入力します
  • 「ECR アクセスロール」:「新しいサービスロールの作成」を選択します
  • 「サービスロール名」:「AppRunnerECRAccessRole-GuildChatServer」を入力

これらを入力し、「次へ」を選択します。

クリックすると拡大します

  • サービス名」: 「guild-chat-server」
  • 環境変数 – オプション」では、「環境変数を追加」を選択し、次の合計 5 つの環境変数を登録します。
    • APPSYNC_API_KEY : 前の手順で控えた「認可モード - API キー」の値
    • APPSYNC_HTTP_DOMAIN : 前の手順で控えた「DNS エンドポイント - HTTP」の値
    • APPSYNC_REALTIME_DOMAIN : 前の手順で控えた「DNS エンドポイント - リアルタイム」の値
    • JWT_PRIVATE_KEY_BASE64 : 前の手順で控えた秘密鍵の値 (BASE64 エンコードしたもの)
    • JWT_PUBLIC_KEY_BASE64 : 前の手順で控えた公開鍵の値 (BASE64 エンコードしたもの)

他はデフォルトの設定で「次へ」を選択します。

※ 本番利用に向けては、秘密鍵の値のような機微な情報の管理には AWS Secrets Manager 等の利用をご検討ください。

クリックすると拡大します

確認および作成」の画面で入力内容を確認後、「作成とデプロイ」を選択します。数分待ち、正常にでデプロイされたことを確認してください。

クリックすると拡大します

登録する環境変数の解説

  • APPSYNC_API_KEY : バックエンドが AppSync HTTP API へパブリッシュする際や、クライアントが WebSocket API に接続する際に利用する API_KEY です。「AWS App Sync」で作成した、「GuildChatAPI」の「設定」から確認が可能で、デフォルトの有効期限が 7 日と短くなっている為、必要に応じて有効期限を延長するよう編集してください。

クリックすると拡大します

  • APPSYNC_HTTP_DOMAIN : バックエンドがAppSync HTTP APIへパブリッシュする際に利用するエンドポイントです。「AWS App Sync」で作成した、「GuildChatAPI」の「設定」から確認可能です。
  • APPSYNC_REALTIME_DOMAIN : クライアントがWebSocket APIに接続する際に利用するWebSocketのエンドポイントです。「AWS App Sync」で作成した、「GuildChatAPI」の「設定」から確認可能です。

クリックすると拡大します

  • JWT_PRIVATE_KEY_BASE64 : JWTトークンに署名するための秘密鍵を Base64 エンコードしたもの。
  • JWT_PUBLIC_KEY_BASE64 : JWTトークンの署名を検証するための公開鍵を Base64 エンコードしたもの。

4-5. Lambda 認証のための URL 設定

最後に、Lambda 認証ハンドラーが JWKS エンドポイントにアクセスできるように環境変数を設定します。

AWS Lambda の認証ハンドラー関数 (guild-chat-auth-handler)「設定」タブから「環境変数」を選択し、「編集」を選択します。

クリックすると拡大します

環境変数の追加」を選択し 1 つの環境変数を追加します。

  • 「キー」:「JWKS_URL」
  • 「値」: 「http://xxxxxxxxxxxx.ap-northeast-1.awsapprunner.com/jwks」※ 作成した AWS App Runner が発行したデフォルトドメインに “/jwks” を加えた値を入力します

保存」を選択します。

クリックすると拡大します


5. 動作確認

AWS App Runner が発行したデフォルトドメインを Webブラウザで開ききます。表示されている任意のギルドに参加し、チャットメッセージを送信してみましょう。複数のブラウザや、シークレット モードなどを利用して複数のセッションからチャットに参加することで、リアルタイムにチャットメッセージが送受信できていることを確認できます。

ログイン画面 : ユーザー名とギルド名を入力してギルドに参加します。(本サンプルではユーザー名は任意です)

チャット画面 : リアルタイムにチャットメッセージが送受信できていることを確認できます。
※ もし送信したメッセージが画面に反映されない場合は、画面上部に「接続済み」の表示が出ているかの確認、「Enter」キーではなく「送信」ボタンを押下で送信、をお試しください。


6. リソースの削除

以上でサンプルチャットアプリの動作確認は完了です。不要なコスト発生を防ぐため、リソースの後片付けをしっかりやりましょう。

  • AWS AppSync Event API
    • AWS AppSync」-「API」-「GuildChatAPI」を選択し、「削除
  • AWS Lambda 関数
    • AWS Lambda」-「guild-chat-auth-handler」の画面から、右上の「アクション」-「関数の削除
  • AWS App Runner サービス
    • AWS App Runner」-「サービス」-「guild-chat-server」の画面から、右上の「アクション」-「削除
  • ECR リポジトリ
    • ECR」-「リポジトリ」から「guild-chat-server」を選択し、右上の「削除
  • HAQM CloudWatch ロググループ
    • HAQM CloudWatch」-「ロググループ」から、以下の 3 つのロググループを選択し、右上の「アクション」-「ロググループの削除
      • /aws/apprunner/guild-chat-server/xxxxxxxxxxxxxxxxxxxxxxxx/application
      • /aws/apprunner/guild-chat-server/xxxxxxxxxxxxxxxxxxxxxxxx/service
      • /aws/lambda/guild-chat-auth-handler

7. まとめ

AWS AppSync Events の登場により、ゲーム開発者はこれまで技術的に難しかったリアルタイムコミュニケーション機能を手軽に実装できるようになりました。従来の WebSocket サーバー構築・運用から解放され、スケーラビリティやコスト効率に優れたソリューションを短期間で提供できます。本記事で紹介したギルドチャットシステムは、AWS AppSync Events、Lambda 認証、App Runner を組み合わせることで、セキュリティを確保しながらリアルタイム性の高いコミュニケーション体験を実現します。サーバーレスアーキテクチャと AWS のマネージドサービスの組み合わせは、開発リソースを削減しながら、プレイヤーにとって価値のある機能を素早く提供するための強力な選択肢となるでしょう。


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

大西 啓太郎(Keitaro Onishi)
アマゾン ウェブ サービス ジャパン合同会社
ゲームソリューションアーキテクト

ゲーム会社のエンジニアを経て 2022 年にアマゾンウェブサービスジャパン合同会社に入社。現在は主にゲーム業界のお客様の技術支援を担当しています。

好きな北斗神拳の奥義は北斗残悔拳。

西坂 信哉(Shinya Nishizaka)
アマゾン ウェブ サービス ジャパン合同会社
ゲームソリューションアーキテクト

SIer のインフラエンジニアを経て 2019 年にアマゾンウェブサービスジャパン合同会社に入社。現在は主にゲーム業界のお客様の技術支援を担当しています。

二児の父として育児奮闘中。ときどきアフタヌーンティーに出かけます。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する