すべてのプロダクト
Search
ドキュメントセンター

Server Load Balancer:WebSocket を使用したリアルタイムメッセージングの実装

最終更新日:Sep 25, 2026

WebSocket は、単一の TCP 接続上で全二重通信チャネルを提供するネットワークプロトコルです。クライアントとサーバー間に永続的な接続を確立し、双方がいつでもデータを送受信できるようにします。これにより、新規接続を繰り返し確立する際のオーバーヘッドとレイテンシーを回避でき、従来の HTTP リクエスト/レスポンスモデルよりも効率的です。WebSocket は主にリアルタイム通信を必要とするアプリケーションで使用されます。Application Load Balancer (ALB) はデフォルトで WebSocket プロトコルをサポートしています。

WebSocket の概要

WebSocket を使用する理由

Web 技術の進化に伴い、ライブチャットルームやリアルタイムコメントなどの機能を実現するため、アプリケーションがサーバーからリアルタイムでデータをプッシュする必要性が高まっています。従来のポーリング方式では、クライアントのブラウザが最新データを取得するために繰り返し HTTP リクエストをサーバーに送信しますが、これには大きな欠点があります。大きな HTTP ヘッダーと小さなデータペイロードによる頻繁なリクエストは、サーバーの負荷を増加させ、帯域幅を浪費します。

これらの問題に対処するため、HTML5 では WebSocket プロトコルが導入されました。これは、クライアントとサーバー間の通信をより効率的に行うソリューションを提供します。WebSocket は全二重通信をサポートしており、サーバーとクライアントが同時にデータを送受信できます。これにより、サーバーはポーリングリクエストを待つことなく、新しいデータをクライアントに能動的にプッシュできます。この双方向のリアルタイム通信メカニズムは、データ転送効率を向上させ、不要なネットワークリクエストを削減し、サーバーリソースと帯域幅を節約することで、よりスムーズで応答性の高いユーザーエクスペリエンスを提供します。

WebSocket の主な特徴

通信は標準的な TCP 3 ウェイハンドシェイクから始まります。その後、クライアントはプロトコルアップグレードハンドシェイクと呼ばれる特別な HTTP リクエストを送信します。このハンドシェイクが成功すると、接続は HTTP から WebSocket に切り替わります。その後のクライアントとサーバー間のすべての通信は WebSocket プロトコルを使用することで、同じ接続上での双方向データ交換が可能になります。

WebSocket 接続が確立されると、その接続はアクティブな状態を維持します。この永続的な低レイテンシー接続は、継続的な双方向データ転送を可能にし、データ交換効率を向上させます。

image

WebSocket はデータフレームを使用して通信します。データフレームには独自のフレームプロトコル形式があり、簡潔なヘッダーを持ちます。データはテキストまたはバイナリとして送信できます。この方法により、永続的な接続におけるプロトコルのオーバーヘッドが削減され、ネットワーク通信がより効率的になります。サーバーリソースと帯域幅を節約しながら、よりスムーズでリアルタイムのインタラクティブなエクスペリエンスを提供します。

WebSocket プロトコルの詳細については、公式ドキュメント「The WebSocket Protocol」をご参照ください。

WebSocket のユースケース

WebSocket は、AI アプリケーション、オンラインチャットルーム、リアルタイム通知システム、マルチプレイヤーオンラインゲーム、リアルタイム市場データフィードなど、高速でリアルタイムな双方向通信を必要とするアプリケーションに最適です。

シナリオ例

ある企業が、Alibaba Cloud 上に Web ベースのオンラインチャットアプリケーションをデプロイしたいと考えています。ユーザーはドメイン名を通じてバックエンドサービスにアクセスし、リアルタイム通信を行うことができます。インスタントメッセージングアプリケーションとして、低レイテンシーで効率的なリアルタイム双方向通信が求められます。

この企業の Web サイトサービスは、高い同時実行性と永続的な接続管理という課題に直面しています。ユーザー数が増加すると、従来の HTTP モデルでは多数の同時ユーザーによるリアルタイム通信をサポートできません。各やり取りに新しい接続が必要なため、サーバーの負荷が急激に増加し、パフォーマンスが低下します。

このシナリオでは、ALB を WebSocket プロトコルと組み合わせて使用することで、高い同時実行性の下で永続的な接続を効果的に管理できます。アプリケーションをサーバーグループ全体にデプロイし、Redis を使用してメッセージ同期を行うことで、高可用性を確保します。これにより、オンラインチャットルームアプリケーションに信頼性の高い効率的なリアルタイムメッセージングソリューションを提供します。

image

注意事項

ALB インスタンスの HTTP リスナーは、デフォルトで WebSocket プロトコルをサポートしています。ALB はローリングアップデートをサポートしているため、設定変更によって既存の永続的な接続が中断されることはありません。

以下の点にご注意ください。

  • ALB インスタンスとバックエンドサーバー間の接続が HTTP/1.1 などの特定の HTTP バージョンを使用する場合、バックエンドサーバーもその HTTP バージョンをサポートすることを推奨します。

  • HTTP リスナーのデフォルトの接続リクエストタイムアウトは 60 秒です。ALB とバックエンドサーバー間で 60 秒以上データ交換がない場合、ALB は接続を切断します。

    • デフォルトの 60 秒のタイムアウトでは不十分な場合は、リスナーの接続リクエストタイムアウトを変更できます。

    • 接続を維持するには、少なくとも 60 秒ごとに 1 回パケットを交換するキープアライブメカニズムを実装する必要があります。

前提条件

  • インターネット向け ALB インスタンスが必要です。詳細については、「ALB インスタンスの作成と管理」をご参照ください。

  • ECS01、ECS02、ECS03 の 3 つの ECS インスタンスが必要です。

    • 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 のデプロイ

  1. ECS03 インスタンスにログオンします。

  2. 以下のコマンドをコピーして実行し、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
    
  3. コマンドがエラーなく実行され、出力に Redis サービスが active (running) 状態であることが表示された場合、デプロイと設定は成功です。

    ● redis.service - Redis persistent key-value database
       Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
       Active: active (running) since ...
     Main PID: 12345 (redis-server)
       CGroup: /system.slice/redis.service
               └─12345 /usr/bin/redis-server 0.0.0.0:6379
    

ECS01 への WebSocket のデプロイ

  1. ECS01 インスタンスにログオンします。

  2. sudo pip3 install flask flask-socketio flask-cors redis を実行して依存関係をインストールします。

  3. vi ECS01_ws.py を実行し、i キーを押して編集モードに入ります。

  4. 以下のコードをコピーして貼り付けます。

    テストサービスのサンプルコード

    説明

    13 行目の redis_url 内の IP アドレスを、Redis サーバー (ECS03) の IP アドレスに置き換えてください。

    import os
    import redis
    from flask import Flask, render_template, request
    from flask_cors import CORS
    from flask_socketio import SocketIO, emit, disconnect
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret!'
    # Cross-Origin Resource Sharing (CORS) を有効化
    CORS(app)
    # Redis をメッセージキューおよびステートストアとして設定
    redis_url = "redis://192.168.*.*:6379/0"  # Redis サーバーの IP アドレスに置き換えてください
    redis_client = redis.StrictRedis.from_url(redis_url)
    # デバッグを容易にするためにログレベルを DEBUG に設定
    socketio = SocketIO(app, message_queue=redis_url, manage_session=True, logger=True, engineio_logger=True, cors_allowed_origins="*")
    SESSION_PREFIX = "session:"
    def set_session_data(session_id, key, value):
        redis_client.hset(f"{SESSION_PREFIX}{session_id}", key, value)
    def get_session_data(session_id, key):
        return redis_client.hget(f"{SESSION_PREFIX}{session_id}", key)
    def delete_session_data(session_id):
        redis_client.delete(f"{SESSION_PREFIX}{session_id}")
    @app.route('/')
    def index():
        return render_template('index.html')
    @socketio.on('connect')
    def handle_connect():
        try:
            session_id = request.sid  # クライアントのセッション ID を取得
            print(f"Session {session_id} connected.")
            welcome_message = "You have entered the chat room!"
            emit('message', welcome_message)
            set_session_data(session_id, "username", '')  # ユーザー名を空として初期化
        except Exception as e:
            print(f"Error during connection: {str(e)}")
    @socketio.on('disconnect')
    def handle_disconnect():
        try:
            session_id = request.sid
            username = get_session_data(session_id, "username")
            if username:
                username = username.decode()
                leave_message = f"{username} has left the chat room."
                emit('message', leave_message, broadcast=True)
                print(leave_message)
            delete_session_data(session_id)
            print(f"Session {session_id} disconnected.")
        except Exception as e:
            print(f"Error during disconnection: {str(e)}")
    @socketio.on('set_username')
    def handle_set_username(username):
        session_id = request.sid
        set_session_data(session_id, "username", username)
        print(f"Username for client {session_id} set to {username}")
        emit('message', f"Your username has been set to: {username}")
    @socketio.on('message')
    def handle_message(msg):
        session_id = request.sid
        username = get_session_data(session_id, "username")
        if username:
            username = username.decode()
            formatted_message = f"{username}: {msg}"
            emit('message', formatted_message, broadcast=True)
            print(formatted_message)
        else:
            warning_message = "Failed to send message: Please set a username first."
            emit('message', warning_message)
            print(warning_message)
    if __name__ == '__main__':
        # templates ディレクトリが存在することを確認
        if not os.path.exists('templates'):
            os.makedirs('templates')
        # Flask テンプレート (index.html) を使用
        html_code = '''<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Chat Room</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                display: flex;
                flex-direction: column;
                align-items: center;
                margin: 0;
                padding: 0;
                background-color: #f0f0f0;
            }
            h1 {
                color: #333;
            }
            .chat-container {
                width: 90%;
                max-width: 600px;
                background: white;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            }
            .user-container, .message-container {
                display: flex;
                margin-bottom: 10px;
            }
            .user-container input, .message-container input {
                flex: 1;
                padding: 10px;
                margin-right: 10px;
                border: 1px solid #ccc;
                border-radius: 4px;
            }
            .message-container {
                margin-top: 10px;
            }
            button {
                padding: 10px;
                background-color: #0056b3;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
            }
            button:hover {
                background-color: #004099;
            }
            #messages {
                border: 1px solid #ccc;
                padding: 10px;
                height: 300px;
                overflow-y: scroll;
                margin-bottom: 10px;
                border-radius: 4px;
                background-color: #f9f9f9;
            }
        </style>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    </head>
    <body>
        <h1>Online Chat Room</h1>
        <div class="chat-container">
            <div class="user-container">
                <input type="text" id="username" autocomplete="off" placeholder="Enter a username">
                <button onclick="setUsername()">Set Username</button>
            </div>
            <div id="messages"></div>
            <div class="message-container">
                <input type="text" id="myMessage" autocomplete="off" placeholder="Enter a message...">
                <button onclick="sendMessage()">Send</button>
            </div>
        </div>
        <script>
            var socket = io({ transports: ['websocket', 'polling', 'flashsocket'] });
            var usernameSet = false;
            socket.on('connect', function() {
                console.log("Connected to the server!");
                socket.on('message', function(msg){
                    $('#messages').append($('<div>').text(msg));
                    $('#messages').scrollTop($('#messages')[0].scrollHeight);
                });
            });
            function setUsername() {
                var username = $('#username').val();
                if (username) {
                    socket.emit('set_username', username);
                    usernameSet = true;  // ユーザー名が設定されたことをマーク
                } else {
                    alert("Username cannot be empty!");
                }
            }
            function sendMessage() {
                if (usernameSet) {
                    var message = $('#myMessage').val();
                    if (message) {
                        socket.send(message);
                        $('#myMessage').val('');
                    } else {
                        alert("Message cannot be empty!");
                    }
                } else {
                    alert("Please set a username first!");
                }
            }
        </script>
    </body>
    </html>
    '''
        # テンプレートをファイルに保存
        with open('templates/index.html', 'w') as file:
            file.write(html_code)
        socketio.run(app, host='0.0.0.0', port=5000)
    
  5. Esc キーを押し、:wq を入力して変更を保存します。

  6. sudo python3 ECS01_ws.py コマンドを実行してスクリプトを実行します。

  7. 以下の出力が表示された場合、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 のデプロイ

  1. ECS02 インスタンスにログオンします。

  2. sudo pip3 install flask flask-socketio flask-cors redis を実行して依存関係をインストールします。

  3. vi ECS02_ws.py を実行し、i キーを押して編集モードに入ります。

  4. 以下のコードをコピーして貼り付けます。

    テストサービスのサンプルコード

    説明

    13 行目の redis_url 内の IP アドレスを、Redis サーバー (ECS03) の IP アドレスに置き換えてください。

    import os
    import redis
    from flask import Flask, render_template, request
    from flask_cors import CORS
    from flask_socketio import SocketIO, emit, disconnect
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret!'
    # Cross-Origin Resource Sharing (CORS) を有効化
    CORS(app)
    # Redis をメッセージキューおよびステートストアとして設定
    redis_url = "redis://192.168.*.*:6379/0"  # Redis サーバーの IP アドレスに置き換えてください
    redis_client = redis.StrictRedis.from_url(redis_url)
    # デバッグを容易にするためにログレベルを DEBUG に設定
    socketio = SocketIO(app, message_queue=redis_url, manage_session=True, logger=True, engineio_logger=True, cors_allowed_origins="*")
    SESSION_PREFIX = "session:"
    def set_session_data(session_id, key, value):
        redis_client.hset(f"{SESSION_PREFIX}{session_id}", key, value)
    def get_session_data(session_id, key):
        return redis_client.hget(f"{SESSION_PREFIX}{session_id}", key)
    def delete_session_data(session_id):
        redis_client.delete(f"{SESSION_PREFIX}{session_id}")
    @app.route('/')
    def index():
        return render_template('index.html')
    @socketio.on('connect')
    def handle_connect():
        try:
            session_id = request.sid  # クライアントのセッション ID を取得
            print(f"Session {session_id} connected.")
            welcome_message = "You have entered the chat room!"
            emit('message', welcome_message)
            set_session_data(session_id, "username", '')  # ユーザー名を空として初期化
        except Exception as e:
            print(f"Error during connection: {str(e)}")
    @socketio.on('disconnect')
    def handle_disconnect():
        try:
            session_id = request.sid
            username = get_session_data(session_id, "username")
            if username:
                username = username.decode()
                leave_message = f"{username} has left the chat room."
                emit('message', leave_message, broadcast=True)
                print(leave_message)
            delete_session_data(session_id)
            print(f"Session {session_id} disconnected.")
        except Exception as e:
            print(f"Error during disconnection: {str(e)}")
    @socketio.on('set_username')
    def handle_set_username(username):
        session_id = request.sid
        set_session_data(session_id, "username", username)
        print(f"Username for client {session_id} set to {username}")
        emit('message', f"Your username has been set to: {username}")
    @socketio.on('message')
    def handle_message(msg):
        session_id = request.sid
        username = get_session_data(session_id, "username")
        if username:
            username = username.decode()
            formatted_message = f"{username}: {msg}"
            emit('message', formatted_message, broadcast=True)
            print(formatted_message)
        else:
            warning_message = "Failed to send message: Please set a username first."
            emit('message', warning_message)
            print(warning_message)
    if __name__ == '__main__':
        # templates ディレクトリが存在することを確認
        if not os.path.exists('templates'):
            os.makedirs('templates')
        # Flask テンプレート (index.html) を使用
        html_code = '''<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Chat Room</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                display: flex;
                flex-direction: column;
                align-items: center;
                margin: 0;
                padding: 0;
                background-color: #f0f0f0;
            }
            h1 {
                color: #333;
            }
            .chat-container {
                width: 90%;
                max-width: 600px;
                background: white;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            }
            .user-container, .message-container {
                display: flex;
                margin-bottom: 10px;
            }
            .user-container input, .message-container input {
                flex: 1;
                padding: 10px;
                margin-right: 10px;
                border: 1px solid #ccc;
                border-radius: 4px;
            }
            .message-container {
                margin-top: 10px;
            }
            button {
                padding: 10px;
                background-color: #0056b3;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
            }
            button:hover {
                background-color: #004099;
            }
            #messages {
                border: 1px solid #ccc;
                padding: 10px;
                height: 300px;
                overflow-y: scroll;
                margin-bottom: 10px;
                border-radius: 4px;
                background-color: #f9f9f9;
            }
        </style>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    </head>
    <body>
        <h1>Online Chat Room</h1>
        <div class="chat-container">
            <div class="user-container">
                <input type="text" id="username" autocomplete="off" placeholder="Enter a username">
                <button onclick="setUsername()">Set Username</button>
            </div>
            <div id="messages"></div>
            <div class="message-container">
                <input type="text" id="myMessage" autocomplete="off" placeholder="Enter a message...">
                <button onclick="sendMessage()">Send</button>
            </div>
        </div>
        <script>
            var socket = io({ transports: ['websocket', 'polling', 'flashsocket'] });
            var usernameSet = false;
            socket.on('connect', function() {
                console.log("Connected to the server!");
                socket.on('message', function(msg){
                    $('#messages').append($('<div>').text(msg));
                    $('#messages').scrollTop($('#messages')[0].scrollHeight);
                });
            });
            function setUsername() {
                var username = $('#username').val();
                if (username) {
                    socket.emit('set_username', username);
                    usernameSet = true;  // ユーザー名が設定されたことをマーク
                } else {
                    alert("Username cannot be empty!");
                }
            }
            function sendMessage() {
                if (usernameSet) {
                    var message = $('#myMessage').val();
                    if (message) {
                        socket.send(message);
                        $('#myMessage').val('');
                    } else {
                        alert("Message cannot be empty!");
                    }
                } else {
                    alert("Please set a username first!");
                }
            }
        </script>
    </body>
    </html>
    '''
        # テンプレートをファイルに保存
        with open('templates/index.html', 'w') as file:
            file.write(html_code)
        socketio.run(app, host='0.0.0.0', port=5000)
                      
  5. Esc キーを押し、:wq を入力して変更を保存します。

  6. sudo python3 ECS02_ws.py コマンドを実行してスクリプトを実行します。

  7. 以下の出力が表示された場合、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:サーバーグループの設定

  1. ALB コンソール にログオンします。

  2. 上部メニューで、インスタンスがデプロイされているリージョンを選択します。

  3. 左側のナビゲーションペインで、サーバーグループ をクリックします。

  4. サーバーグループの作成 をクリックします。サーバーグループの作成 ページで、次のパラメーターを設定し、その他はデフォルト値のままにして、作成 をクリックします。

    パラメータ

    説明

    [サーバーグループタイプ]

    サーバタイプ を選択します。

    VPC

    バックエンドサーバー ECS01 と ECS02 が配置されている VPC を選択します。

    バックエンドサーバーは ALB インスタンスと同じ VPC 内に配置する必要があります。

  5. サーバーグループが作成されました ダイアログボックスで、バックエンドサーバーの追加 をクリックします。

  6. バックエンドサーバーの追加 ページで、ECS01 と ECS02 を選択してサーバーグループに追加します。ポートを 5000 に設定します。これは、このチュートリアルで WebSocket アプリケーションが使用するポートです。

ステップ 3:HTTP リスナーの設定

  1. ALB コンソール にログオンします。

  2. 上部メニューで、インスタンスがデプロイされているリージョンを選択します。

  3. 左側のナビゲーションペインで、インスタンス を選択します。

  4. インスタンス ページで、目的のインスタンスを見つけ、操作 列の リスナーの作成 をクリックします。

  5. リスナーの設定 ページで、次のパラメーターを設定し、その他のパラメーターはデフォルト値のままにします。次に、次へ をクリックします。

    パラメータ

    説明

    [リスナープロトコルの選択]

    [HTTP] を選択します。

    [リスニングポート]

    ポートを 5000 に設定します。

  6. サーバーグループを選択 ページで、次のパラメーターを設定し、その他のパラメーターはデフォルト値のままにして、次へ をクリックします。

    パラメータ

    説明

    [サーバーグループを選択]

    作成したサーバーグループを選択します。

  7. 確定 ページで設定を確認して 送信 をクリックします。その後、リスナーが作成されるまで待ちます。

ステップ 4:名前解決の設定

本番環境では、CNAME レコードを作成して、カスタムドメイン名を ALB インスタンスのドメイン名にマッピングすることを推奨します。

  1. 左側のナビゲーションウィンドウで、ALB > インスタンス を選択します。

  2. インスタンス ページで、作成された ALB インスタンスの DNS 名をコピーします。

  3. 次の手順に従って CNAME レコードを追加します。

    説明

    ドメイン名が Alibaba Cloud 以外のプロバイダーによって登録されている場合は、DNS 設定を行う前に、ドメイン名を Alibaba Cloud DNS コンソールに追加する必要があります。詳細については、「ドメイン名の管理」をご参照ください。ドメイン名が Alibaba Cloud に登録されている場合は、次の手順に進んでください。

    1. Alibaba Cloud DNS コンソールにログインします。

    2. インターネットの権威ある DNS 解決 ページで、対象のドメイン名を見つけ、操作 列の 解決設定 をクリックします。

    3. 解決設定 ページで、Add Record をクリックします。

    4. Add Record パネルで、次のパラメーターを設定して CNAME レコードを構成し、OK をクリックします。

      パラメーター

      説明

      レコードタイプ

      ドロップダウンリストから [CNAME] を選択します。

      ホストレコード

      ドメイン名のプレフィックス。このチュートリアルでは @ を使用します。

      説明

      ルートドメインを使用するには、ホスト名を @ に設定します。

      Query Source

      デフォルトを選択します。

      レコード値

      コピーした ALB インスタンスの DNS 名を入力します。

      TTL

      Time to Live (TTL) は、DNS レコードが DNS サーバーにキャッシュされる期間です。デフォルト値を使用します。

ステップ 5:結果の確認

2 台の別々のコンピューターのブラウザでアプリケーションを開き、メッセージを交換することで、ALB が WebSocket 経由でリアルタイムメッセージを配信することを確認します。

  1. ブラウザで http://<your-domain-name>:5000 にアクセスして、オンラインチャットルームアプリケーションにアクセスします。

    [オンラインチャットルーム] インターフェースが読み込まれます。チャットメッセージエリアに "You have entered the chat room!" というメッセージが表示され、WebSocket 接続が確立されたことを示します。ページには、ユーザー名設定エリアと [ユーザー名の設定] ボタン、およびメッセージ送信エリアと [送信] ボタンがあります。

    ブラウザの開発者ツールを開くと、[ネットワーク] タブにブラウザが WebSocket プロトコルを使用して通信していることが表示されます。

    [ネットワーク] パネルで、フィルターを websocket に設定します。ステータスコード 101 の WebSocket リクエストは、プロトコルアップグレードが成功したことを示します。接続ステータスが Pending となっているのは、永続的な WebSocket 接続が確立されアクティブであることを意味します。

  2. チャット用のユーザー名を入力し、[ユーザー名の設定] をクリックします。

  3. 各コンピューターで複数のチャットメッセージを入力し、[送信] をクリックしてアプリケーションをテストします。

    両方のブラウザがリアルタイムでメッセージを受信します。

    オンラインチャットルームアプリケーションが正常にデプロイされました。ページには [ユーザー名] 入力ボックスと [ユーザー名の設定] ボタン、チャットメッセージ表示エリア、および下部にメッセージ入力ボックスと [送信] ボタンがあります。User1 や User2 などの複数のユーザーが、チャットルームでリアルタイムに会話できます。

  4. これにより、ALB が WebSocket 経由でリアルタイムかつ高可用性のメッセージングを提供することが確認されました。

よくある質問

WebSocket Secure を使用するにはどうすればよいですか?

WebSocket Secure は、WebSocket プロトコルの暗号化バージョンです。

HTTPS リスナーは、デフォルトで WebSocket Secure をサポートしています。WebSocket Secure を使用するには、リスナーを設定する際に HTTPS を選択してください。

WebSocket の使用には料金が発生しますか?

WebSocket および WebSocket Secure には追加料金は発生しません。

どのリージョンで WebSocket がサポートされていますか?

ALB をサポートするすべてのリージョンで、WebSocket および WebSocket Secure もサポートされています。

関連ドキュメント

このチュートリアルでは、テスト目的で ECS インスタンスに Redis をデプロイする方法を示しています。ただし、単一の Redis サーバーは潜在的な単一障害点となります。本番環境では、高可用性を確保するために Tair の使用を推奨します。詳細については、「Tair のクイックスタート」をご参照ください。