WebSocket は、単一の TCP 接続上で全二重の通信チャネルを提供するネットワークプロトコルです。クライアントとサーバー間に永続的な接続を確立し、双方が能動的にデータを送受信できるようにします。この設計は、新規接続を頻繁に確立する際のオーバーヘッドとレイテンシーを低減し、従来の HTTP リクエスト/レスポンスモデルよりも効率的です。WebSocket は主に、リアルタイム通信を必要とするアプリケーションで使用されます。Classic Load Balancer (CLB) は、デフォルトで WebSocket プロトコルをサポートしています。
WebSocket の概要
WebSocket を使用する理由
Web 技術の進化に伴い、ライブチャットルームやリアルタイムコメントなどの機能では、サーバーがデータをリアルタイムにプッシュすることが求められるようになっています。従来のポーリング方式では、クライアントのブラウザが HTTP リクエストを繰り返しサーバーに送信して最新データをフェッチしますが、重大な欠点があります。大きな HTTP ヘッダーと小さなデータペイロードを伴う頻繁なリクエストは、サーバーの負荷を増加させ、帯域幅を圧迫します。
これらの問題に対応するため、HTML5 は WebSocket プロトコルを導入し、クライアントとサーバー間の通信に、より効率的なソリューションを提供します。WebSocket は全二重通信をサポートしており、サーバーとクライアントは同時にデータを送受信できます。これにより、サーバーはポーリングリクエストを待たずに、新しいデータをクライアントへ能動的にプッシュできます。この双方向リアルタイム通信メカニズムは、データ転送の効率を向上させ、不要なネットワークリクエストを削減し、サーバーリソースと帯域幅を節約します。その結果、よりスムーズで応答性の高いユーザーエクスペリエンスを提供できます。
WebSocket の主な機能
通信は、標準の TCP 3 ウェイハンドシェイクで始まります。次に、クライアントがプロトコルアップグレードハンドシェイクと呼ばれる特別な HTTP リクエストを送信します。このハンドシェイクが成功すると、接続は HTTP から WebSocket に切り替わります。以降、クライアントとサーバーは WebSocket プロトコルを使用し、同一の接続上で双方向のデータ交換を行えるようになります。
WebSocket 接続が確立されると、その接続はアクティブな状態を保ちます。この永続的な低レイテンシー接続により、継続的な双方向のデータ転送が可能になり、データ交換の効率が向上します。
WebSocket はデータフレームを使用して通信します。データフレームには、簡潔なヘッダーを備えた独自のフレームプロトコル形式があります。データはテキスト形式またはバイナリ形式で送信できます。この方式により、永続的な接続におけるプロトコルオーバーヘッドが削減され、ネットワーク通信がより効率的になります。サーバーリソースと帯域幅を節約しながら、よりスムーズなリアルタイムのインタラクティブエクスペリエンスを提供します。
WebSocket プロトコルの詳細については、公式ドキュメント「WebSocket プロトコル」をご参照ください。
WebSocket のユースケース
WebSocket は、AI アプリケーション、オンラインチャットルーム、リアルタイム通知システム、マルチプレイヤーオンラインゲーム、リアルタイムマーケットデータフィードなど、高速でリアルタイムな双方向通信を必要とするアプリケーションに最適です。
シナリオ例
ある企業が Alibaba Cloud 上に Web ベースのオンラインチャットアプリケーションをデプロイしたいと考えています。ユーザーはドメイン名を介してバックエンドサービスにアクセスし、リアルタイム通信を行えます。インスタントメッセージアプリケーションとして、低レイテンシーで効率的なリアルタイムの双方向通信が求められます。
この企業の Web サイトサービスでは、高い同時実行性と永続的な接続の管理が課題となっています。ユーザー数が増加すると、従来の HTTP モデルでは、やり取りのたびに新しい接続が必要になるため、リアルタイム通信において多数の同時ユーザーをサポートできません。その結果、サーバー負荷が急増し、パフォーマンスが低下します。
このシナリオでは、CLB と WebSocket プロトコルを使用することで、高い同時実行性の状況下でも永続的な接続を効果的に管理できます。vServer グループ内の複数のバックエンドサーバーに WebSocket アプリケーションをデプロイし、Redis を使用してメッセージ同期を行うことで、サービスは高可用性を実現します。これにより、オンラインチャットアプリケーション向けに、信頼性が高く効率的なリアルタイムメッセージングソリューションを提供できます。
注意事項
CLB の HTTP リスナーは、デフォルトで WebSocket プロトコルをサポートしています。CLB はホットアップデートをサポートしているため、設定変更によって既存の永続的な接続が影響を受けることはありません。
次の点にご注意ください:
-
CLB とバックエンドサーバー間の接続で HTTP/1.1 など特定の HTTP バージョンを使用する場合は、バックエンドサーバー側でも同じ HTTP バージョンをサポートする Web サーバーを使用する必要があります。
-
HTTP リスナーの接続リクエストタイムアウトはデフォルトで 60 秒です。CLB とバックエンドサーバーの間で 60 秒を超えてメッセージの送受信がない場合、CLB は自ら接続をクローズします。
-
デフォルトの 60 秒のタイムアウトが要件を満たさない場合は、リスナーの [接続リクエストタイムアウト] を変更できます。
-
接続を維持するには、設定されたタイムアウト時間内にパケットを交換するキープアライブメカニズムを実装する必要があります。
-
前提条件
-
Classic Load Balancer (CLB) インスタンスを作成しておく必要があります。
-
3 つの Elastic Compute Service (ECS) インスタンス (ECS01、ECS02、ECS03) が必要です。
-
ECS01 と ECS02 は WebSocket アプリケーションのデプロイに、ECS03 は Redis のデプロイに使用します。
-
このチュートリアルでは、すべてのサーバーで CentOS 7.9 を実行します。
-
ECS01、ECS02、ECS03 は同じセキュリティグループに配置することを推奨します。異なるセキュリティグループに配置する場合は、サーバー間で必要な通信ポートのトラフィックを許可するルールを設定してください。
-
-
ICP 登録が完了した登録済みドメイン名が必要です。詳細については、「Alibaba Cloud ドメイン名の登録」および「ICP 申請」をご参照ください。
操作手順
手順1:サービスのデプロイ
ECS03 インスタンスに Redis を、ECS01 および ECS02 インスタンスに WebSocket アプリケーションをデプロイします。
このトピックでは、デモンストレーションのために、CentOS 7.9 上のシンプルな Python ベースのオンラインチャットルームを使用します。この例は参考用です。本番環境では、独自のアプリケーションを使用してください。
ECS03 への Redis のデプロイ
-
ECS03 インスタンスにログオンします。
-
次のコマンドをコピーして実行し、Redis をインストールして設定します。
# EPEL (Extra Packages for Enterprise Linux) をインストール sudo yum install epel-release -y # Redis をインストール sudo yum install redis -y # Redis サービスを開始して有効化 sudo systemctl start redis sudo systemctl enable redis # リモート接続を許可するように Redis 設定ファイルを編集 sudo sed -i 's/^bind 127.0.0.1$/bind 0.0.0.0/' /etc/redis.conf sudo sed -i 's/^protected-mode yes/protected-mode no/' /etc/redis.conf # 変更を有効にするために Redis サービスを再起動 sudo systemctl restart redis # Redis のステータスを確認 sudo systemctl status redis -
コマンドがエラーなく実行され、出力で Redis サービスが アクティブ (実行中) の状態であることが表示された場合、デプロイと設定は成功です。
● redis.service – Redis persistent key-value database Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled) Drop-In: /etc/systemd/redis.service.d └─limit.conf Active: active (running) since Thu 2xxx xxx xxx xxx CST; 6s ago Process: 14715 ExecStop=/usr/libexec/redis-shutdown (code=exited, status=0/SUCCESS) Main PID: 14730 (redis-server) CGroup: /system.slice/redis.service └─14730 /usr/bin/redis-server 0.0.0.0:6379
ECS01 への WebSocket のデプロイ
-
ECS01 インスタンスにログオンします。
-
sudo pip3 install flask flask-socketio flask-cors redisを実行して、依存関係をインストールします。 -
vi ECS01_ws.pyを実行し、iキーを押して編集モードに入ります。 -
次のコードをコピーして貼り付けます。
-
Escキーを押し、:wqと入力して変更を保存します。 -
sudo python3 ECS01_ws.pyコマンドを実行してスクリプトを実行します。 -
次の出力が表示されると、WebSocket アプリケーションがポート 5000 で開始されています:
Server initialized for threading. * Serving Flask app 'ECS01_ws' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on all addresses. WARNING: This is a development server. Do not use it in a production deployment. * Running on http://192.168.*.*:5000/ (Press CTRL+C to quit)アプリケーションの起動に失敗した場合は、ポートがすでに使用されているか、コマンドまたはコードのコピーに誤りがないかを確認してください。
● redis.service – Redis 永続的キーバリューデータベース
Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/redis.service.d
└─limit.conf
Active: active (running) since Thu 2xxx xxx xxx xxx CST; 6s ago
Process: 14715 ExecStop=/usr/libexec/redis-shutdown (code=exited, status=0/SUCCESS)
Main PID: 14730 (redis-server)
CGroup: /system.slice/redis.service
└─14730 /usr/bin/redis-server 0.0.0.0:6379
ECS02 への WebSocket のデプロイ
-
ECS02 インスタンスにログオンします。
-
sudo pip3 install flask flask-socketio flask-cors redisを実行して、依存関係をインストールします。 -
vi ECS02_ws.pyを実行し、iキーを押して編集モードに入ります。 -
次のコードをコピーして貼り付けます。
-
Escキーを押し、:wqと入力して変更を保存します。 -
sudo python3 ECS02_ws.pyコマンドを実行してスクリプトを実行します。 -
次の出力が表示されると、WebSocket アプリケーションがポート 5000 で開始されています:
Server initialized for threading. * Serving Flask app 'ECS02_ws' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on all addresses. WARNING: This is a development server. Do not use it in a production deployment. * Running on http://192.168.*.*:5000/ (Press CTRL+C to quit)アプリケーションの起動に失敗した場合は、ポートがすでに使用されているか、コマンドまたはコードのコピーに誤りがないかを確認してください。
ステップ 2:vServer グループの設定
-
Classic Load Balancer (CLB) コンソールにログインします。
-
上部メニューで、CLB インスタンスがデプロイされているリージョンを選択します。
-
左側のナビゲーションペインで、インスタンス を選択します。 インスタンス ページで、対象のインスタンスを見つけ、その ID をクリックします。
-
仮想サーバーグループ タブで、VServer Group の作成 をクリックします。 VServer Group の作成 ページで、次のパラメーターを設定します。 他のパラメーターは、デフォルト値を使用するか、必要に応じて変更できます。 設定が完了したら、作成 をクリックし、画面の指示に従います。
パラメーター
説明
[VServer グループ名]
vServer グループ名として RS1 を入力します。
-
仮想サーバーグループ タブで、作成した vServer グループを見つけ、操作 列の 編集 をクリックします。
-
VServer Group の編集 ページで、追加 をクリックします。 サーバー登録 ページで、バックエンドサーバー ECS01 と ECS02 を追加します。 両方のサーバーのポートを、WebSocket アプリケーションが使用するポートである 5000 に設定します。
-
VServer Group の編集 ページで、追加したサーバーを選択し、保存 をクリックします。
ステップ 3:HTTP リスナーの設定
-
Classic Load Balancer (CLB) コンソールにログインします。
-
上部メニューで、CLB インスタンスがデプロイされているリージョンを選択します。
-
左側のナビゲーションペインで、インスタンス を選択します。
-
インスタンス ページで、対象のインスタンスを見つけ、操作 列の リスナーの設定 をクリックします。
-
プロトコルとリスナー ページで、次のパラメーターを設定します。 他のパラメーターは、デフォルト値を使用するか、必要に応じて変更できます。 設定が完了したら、次へ をクリックします。
パラメーター
説明
[リスナープロトコルの選択]
[HTTP] を選択します。
[リスニングポート]
この例では、ポートを 5000 に設定します。
-
バックエンド サーバー ページで、次のパラメーターを設定します。 他のパラメーターは、デフォルト値を使用するか、必要に応じて変更できます。 設定が完了したら、次へ をクリックします。
パラメーター
説明
[サーバーグループを選択]
作成した vServer グループを選択します。
-
[ヘルスチェック] ページでは、パラメーターにデフォルト値を使用するか、必要に応じて変更できます。 その後、次へ をクリックします。
-
確定 ページで、設定を確認し、送信 をクリックしてリスナーを作成します。
ステップ 4:DNS 名前解決の設定
-
Alibaba Cloud に登録されていないドメインの場合、DNS レコードを設定する前に、まず Alibaba Cloud DNS コンソールにドメインを追加する必要があります。
-
CLB インスタンスが内部向けインスタンスの場合、まず Elastic IP アドレス (EIP) を関連付けてから、ドメイン名を EIP にマッピングする A レコードを作成して、パブリックアクセスを有効にする必要があります。
-
左側のナビゲーションペインで、を選択します。
-
インスタンス ページで、対象のインスタンスを選択し、その IP をコピーします。
-
次の手順を実行して、A レコードを追加します。
-
Alibaba Cloud DNS コンソールにログインします。
-
インターネットの権威ある DNS 解決 ページで、目的のドメイン名を見つけ、Actions 列の 解決設定 をクリックします。
-
解決設定 ページで、Add Record をクリックします。
-
Add Record パネルで、次のパラメーターを設定します。その他のパラメーターはデフォルト値のままにするか、必要に応じて変更できます。次に、OK をクリックします。
パラメーター
説明
[Record Type]
ドロップダウンリストから A を選択します。
[Hostname]
ドメイン名のプレフィックスです。
説明ルートドメインの場合は、ホスト名を @ に設定します。
[Record Value]
コピーした CLB インスタンスの IP アドレスを入力します。
-
ステップ 5:結果の検証
異なるパブリック IP アドレスを持つ 2 台のコンピューターを準備します。 各コンピューターでブラウザを使用してチャットメッセージを送受信し、CLB によって WebSocket を介してリアルタイムでメッセージが配信されることを確認します。
-
ブラウザで
http://<your-domain-name>:5000にアクセスして、オンラインチャットルームアプリケーションを開きます。オンラインチャットルームインターフェイスが読み込まれます。チャットメッセージエリアに「チャットルームに入室しました!」というメッセージが表示され、WebSocket 接続が確立されたことを示します。ページには、[ユーザー名を設定] ボタンがあるユーザー名設定エリアと、[送信] ボタンがあるメッセージ送信エリアが含まれます。
ブラウザの開発者ツールを開くと、[ネットワーク] タブで、ブラウザが WebSocket プロトコルを使用して通信していることを確認できます。
[ネットワーク] パネルで、フィルターを
websocketに設定します。ステータスコードが 101 の WebSocket リクエストは、プロトコルのアップグレードが成功したことを示します。接続ステータスは保留中になります。これは、永続的な WebSocket 接続が確立され、アクティブであることを意味します。 -
チャットのユーザー名を入力し、[ユーザー名を設定] をクリックします。
-
各コンピューターで複数のチャットメッセージを入力し、[送信] をクリックしてアプリケーションをテストします。
両方のブラウザがリアルタイムでメッセージを受信します。
オンラインチャットルームアプリケーションは正常にデプロイされました。ページには、[ユーザー名] 入力ボックスと [ユーザー名を設定] ボタン、チャットメッセージ表示エリア、および下部に [送信] ボタンがあるメッセージ入力ボックスが含まれています。田中一郎や鈴木花子などの複数のユーザーがチャットルームでリアルタイムの会話を行うことができます。
-
これにより、CLB と WebSocket を使用することで、リアルタイムで高可用性なメッセージングが可能になることを検証できます。
よくある質問
WebSocket Secure プロトコルを使用するにはどうすればよいですか?
WebSocket Secure は、WebSocket プロトコルの暗号化バージョンです。
HTTPS リスナーは、デフォルトで WebSocket Secure プロトコルをサポートしています。WebSocket Secure プロトコルを使用するには、リスナーを設定する際に HTTPS を選択してください。
WebSocket の使用に料金はかかりますか?
WebSocket および WebSocket Secure プロトコルの使用に追加料金はかかりません。
WebSocket はどのリージョンでサポートされていますか?
CLB をサポートしているすべてのリージョンで、WebSocket および WebSocket Secure もサポートされています。
リファレンス
このチュートリアルでは、テスト用に ECS インスタンスに Redis をデプロイする例を示します。ただし、単一の Redis サーバーは単一障害点 (SPOF) となる可能性があります。本番環境では、高可用性を確保するために Tair を使用することを推奨します。詳細については、「Tair のクイックスタート」をご参照ください。