このチュートリアルでは、永続的な接続により双方向通信を行う WebSocket を使用して、マルチルームのリアルタイム チャット サービスを作成する方法について説明します。WebSocket を使用すると、サーバーに更新をポーリングすることなく、クライアントとサーバーの両方がメッセージを相互に push できます。
セッション アフィニティを使用するように Cloud Run を構成できますが、これはベスト エフォート型アフィニティになります。つまり、新しいリクエストが、別のインスタンスにルーティングされる可能性がまだあるということです。そのため、チャット サービスのユーザー メッセージは、1 つのインスタンスに接続されたクライアント間だけでなく、すべてのインスタンス間で同期する必要があります。
デザインの概要
このサンプル チャット サービスは、Memorystore for Redis インスタンスを使用して、ユーザー メッセージを保存し、すべてのインスタンス間で同期します。Redis は Pub/Sub メカニズムを使用して(Cloud Pub/Sub プロダクトではありません)、任意のインスタンスに接続された登録済みクライアントにデータを push し、HTTP で更新をポーリングしないようにします。
ただし、push 更新があっても、起動されたインスタンスはコンテナに push された新しいメッセージのみを受信します。以前のメッセージを読み込むには、メッセージ履歴を永続ストレージ ソリューションに保存して取得する必要があります。このサンプルでは、Redis の従来のオブジェクト ストアの機能を使用して、メッセージ履歴をキャッシュに保存して取得します。
Redis インスタンスは、アクセス制御されたプライベート IP を使用してインターネットから保護され、Redis インスタンスと同じバーチャル プライベート ネットワークで実行されているサービスに限定されます。したがって、Cloud Run サービスが Redis に接続するには、サーバーレス VPC アクセス コネクタが必要です。サーバーレス VPC アクセスの詳細をご確認ください。
制限事項
このチュートリアルでは、エンドユーザー認証やセッション キャッシュについては説明しません。エンドユーザー認証の詳細については、Cloud Run チュートリアルのエンドユーザー認証をご覧ください。
このチュートリアルでは、チャット メッセージの履歴を制限なく保存し、取得するために、Firestore などのデータベースを実装することはありません。
このサンプル サービスを本番環境で使用できるようにするには、追加の要素が必要です。レプリケーションと自動フェイルオーバーを使用した高可用性を実現するには、スタンダード ティアの Redis インスタンスをおすすめします。
gcloud
のデフォルトを設定する
Cloud Run サービスを gcloud のデフォルトに構成するには:
デフォルト プロジェクトを設定します。
gcloud config set project PROJECT_ID
PROJECT_ID は、このチュートリアルで作成したプロジェクトの名前に置き換えます。
選択したリージョン向けに gcloud を構成します。
gcloud config set run/region REGION
REGION は、任意のサポートされている Cloud Run のリージョンに置き換えます。
Cloud Run のロケーション
Cloud Run はリージョナルです。つまり、Cloud Run サービスを実行するインフラストラクチャは特定のリージョンに配置され、そのリージョン内のすべてのゾーンで冗長的に利用できるように Google によって管理されます。
レイテンシ、可用性、耐久性の要件を満たしていることが、Cloud Run サービスを実行するリージョンを選択する際の主な判断材料になります。一般的には、ユーザーに最も近いリージョンを選択できますが、Cloud Run サービスで使用されている他の Google Cloudプロダクトのロケーションも考慮する必要があります。 Google Cloud プロダクトを複数のロケーションで使用すると、サービスのレイテンシだけでなく、コストにも影響を及ぼす可能性があります。
Cloud Run は、次のリージョンで利用できます。
ティア 1 料金を適用
asia-east1
(台湾)asia-northeast1
(東京)asia-northeast2
(大阪)asia-south1
(ムンバイ、インド)europe-north1
(フィンランド)低 CO2
europe-north2
(ストックホルム)低 CO2
europe-southwest1
(マドリッド)低 CO2
europe-west1
(ベルギー)低 CO2
europe-west4
(オランダ)低 CO2
europe-west8
(ミラノ)europe-west9
(パリ)低 CO2
me-west1
(テルアビブ)northamerica-south1
(メキシコ)us-central1
(アイオワ)低 CO2
us-east1
(サウスカロライナ)us-east4
(北バージニア)us-east5
(コロンバス)us-south1
(ダラス)低 CO2
us-west1
(オレゴン)低 CO2
ティア 2 料金を適用
africa-south1
(ヨハネスブルグ)asia-east2
(香港)asia-northeast3
(ソウル、韓国)asia-southeast1
(シンガポール)asia-southeast2
(ジャカルタ)asia-south2
(デリー、インド)australia-southeast1
(シドニー)australia-southeast2
(メルボルン)europe-central2
(ワルシャワ、ポーランド)europe-west10
(ベルリン)europe-west12
(トリノ)europe-west2
(ロンドン、イギリス)低 CO2
europe-west3
(フランクフルト、ドイツ)europe-west6
(チューリッヒ、スイス)低 CO2
me-central1
(ドーハ)me-central2
(ダンマーム)northamerica-northeast1
(モントリオール)低 CO2
northamerica-northeast2
(トロント)低 CO2
southamerica-east1
(サンパウロ、ブラジル)低 CO2
southamerica-west1
(サンティアゴ、チリ)低 CO2
us-west2
(ロサンゼルス)us-west3
(ソルトレイクシティ)us-west4
(ラスベガス)
Cloud Run サービスをすでに作成している場合は、Google Cloud コンソールの Cloud Run ダッシュボードにリージョンが表示されます。
サンプルコードを取得する
使用するコードサンプルを取得するには:
ローカルマシンにサンプル リポジトリのクローンを作成します。
Node.js
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。
Cloud Run のサンプルコードが含まれているディレクトリに移動します。
Node.js
cd nodejs-docs-samples/run/websockets/
コードの説明
Socket.io は、ブラウザとサーバー間でのリアルタイム双方向通信を可能にするライブラリです。Socket.io は WebSocket の実装ではありませんが、複数の通信プロトコルに対応するシンプルな API を提供する機能を、信頼性の向上、自動再接続、すべてのクライアントまたは一部のクライアントへのブロードキャストなどの追加機能とラップします。
クライアントサイドの統合
クライアントは、接続ごとに新しい Socket インスタンスをインスタンス化します。このサンプルはサーバー側でレンダリングされるため、サーバー URL を定義する必要はありません。ソケット インスタンスはイベントを出力しリッスンできます。
サーバーサイドの統合
サーバーサイドで、Socket.io サーバーが初期化され、HTTP サーバーに接続されます。クライアントサイドと同様に、Socket.io サーバーがクライアントと接続すると、接続ごとにソケット インスタンスが作成され、メッセージの出力やリッスンに使用されます。Socket.io では、「チャットルーム」用の簡易インターフェース、または任意のチャンネルも用意されていて、ソケットが自由に参加または離脱できます。
Socket.io には、ソケットを提供しているサーバーに関係なく、すべてのクライアントにイベントをブロードキャストする Redis アダプタも用意されています。Socket.io では、Redis の Pub/Sub メカニズムを使用するだけで、データは保存しません。
Socket.io の Redis アダプタは、チャットルームのメッセージ履歴の保存に使用された Redis クライアントを再利用できます。各コンテナは Redis インスタンスへの接続を作成します。Cloud Run は多数のインスタンスを作成できます。これは、Redis がサポートする 65,000 接続をかなり下回っています。この量のトラフィックをサポートする必要がある場合は、サーバーレス VPC アクセス コネクタのスループットも評価する必要があります。
再接続
Cloud Run のタイムアウトは最大 60 分です。そのため、タイムアウトが発生する可能性に備えて、再接続ロジックを追加する必要があります。場合によっては、Socket.io が切断または接続エラーイベントの後に自動的に再接続を試みます。クライアントが同じインスタンスに再接続する保証はありません。
すべてのリクエストが閉じるかタイムアウトするまで、アクティブな接続がある間はインスタンスが保持されます。Cloud Run のセッション アフィニティを使用している場合でも、新しいリクエストはアクティブなコンテナにロードバランスされるため、コンテナはスケールインできます。トラフィックの急増後に多数のコンテナが保持されることが懸念される場合は、未使用のソケットが頻繁にクリーンアップされるように最大タイムアウト値を下げることができます。
サービスの配布
Memorystore for Redis インスタンスを作成します。
gcloud redis instances create INSTANCE_ID --size=1 --region=REGION
INSTANCE_ID はインスタンスの名前(
my-redis-instance
など)に置き換え、REGION_ID はすべてのリソースとサービスのリージョン(europe-west1
など)に置き換えます。インスタンスに、デフォルトのサービス ネットワーク範囲から IP 範囲が自動的に割り振られます。このチュートリアルでは、Redis インスタンスのメッセージのローカル キャッシュに 1 GB のメモリを使用します。詳細については、ユースケース用の Memorystore インスタンスの初期サイズの決定をご覧ください。
サーバーレス VPC アクセス コネクタを設定します。
Redis インスタンスに接続するには、Cloud Run サービスが Redis インスタンスの承認済み VPC ネットワークにアクセスする必要があります。
VPC コネクタごとに、コネクタ インスタンスを配置する独自の
/28
サブネットが必要です。この IP 範囲は、VPC ネットワーク内の既存の IP アドレス予約と重複してはいけません。たとえば、10.8.0.0
(/28
)はほとんどの新規プロジェクトで機能しますが、10.9.0.0
(/28
)など、別の未使用のカスタム IP 範囲を指定することもできます。現在予約されている IP 範囲は、Google Cloud コンソールで確認できます。gcloud compute networks vpc-access connectors create CONNECTOR_NAME \ --region REGION \ --range "10.8.0.0/28"
CONNECTOR_NAME は、アプリケーションの名前に置き換えます。
このコマンドは、Redis インスタンスと同じデフォルト VPC ネットワークに、
e2-micro
マシンサイズのコネクタを作成します。コネクタのマシンサイズを大きくすると、コネクタのスループットを向上させることができますが、コストも増加します。また、コネクタは Redis インスタンスと同じリージョンに配置する必要があります。サーバーレス VPC アクセスの構成の詳細をご確認ください。Redis インスタンスの承認済みネットワークの IP アドレスを使用して、環境変数を定義します。
export REDISHOST=$(gcloud redis instances describe INSTANCE_ID --region REGION --format "value(host)")
サービス ID として機能するサービス アカウントを作成します。このアカウントには、デフォルトでは、プロジェクト メンバーシップ以外の権限は付与されません。
gcloud iam service-accounts create chat-identity gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:chat-identity@PROJECT_ID. \ --role=roles/serviceusage.serviceUsageConsumer
コンテナ イメージをビルドして Cloud Run にデプロイします。
gcloud run deploy chat-app --source . \ --vpc-connector CONNECTOR_NAME \ --allow-unauthenticated \ --timeout 3600 \ --service-account chat-identity \ --update-env-vars REDISHOST=$REDISHOST
プロンプトが表示されたら、
y
と入力して必要な API をインストールするように応答します。これが必要なのはプロジェクトに対して 1 回だけです。設定ページに記載されているように、デフォルト値を設定しない場合は、別のプロンプトにプラットフォームとリージョンを指定して応答します。ソースコードからのデプロイで詳細をご確認ください。
試してみる
完成したサービスを試すには:
ブラウザで、前述のデプロイの手順により提供された URL に移動します。
自分の名前とチャットルームを追加してログインします。
チャットルームにメッセージを送信します。
これらのサービスの開発を継続する場合は、 Google Cloud の他のサービスへの Identity and Access Management(IAM)アクセスが制限されます。他の多くのサービスにアクセスするには、追加の IAM ロールをこれらのサービスに付与する必要があることにご注意ください。