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

Server Load Balancer:WebSocket を使用してリアルタイムメッセージングを有効にする

最終更新日:Feb 15, 2025

WebSocket は、単一の TCP 接続を介した全二重通信をサポートする通信プロトコルです。 WebSocket は、永続的な接続を介してクライアントとサーバー間の双方向通信を確立するように設計されています。 WebSocket では、接続の作成または終了の頻度が低いため、オーバーヘッドが少なく、ネットワーク遅延も少なくて済みます。 従来の要求 - 応答 HTTP プロトコルと比較して、WebSocket はリアルタイムのインタラクションでより高い効率をサポートします。 WebSocket は、リアルタイム通信を必要とするシナリオに適しています。 Application Load Balancer (ALB) は、デフォルトで WebSocket をサポートしています。

WebSocket の概要

WebSocket を使用する理由

インターネット技術の急速な発展に伴い、Web アプリケーションは多様化しています。 ライブストリーミングチャットや弾幕など、一部のシナリオでは、サーバー側のリアルタイムプッシュが必要です。 従来のソリューションでは、ラウンドロビンアルゴリズムを使用して、1 秒などの一定の間隔でクライアントブラウザからサーバーへの HTTP リクエストを開始します。 次に、サーバーは最新のデータをクライアントに返します。 ただし、このソリューションには欠点があります。 クライアントは頻繁にリクエストを開始する必要があり、リクエストには大きな HTTP ヘッダーが含まれていますが、有用な情報は少なくなっています。 リクエストはサーバーの負荷を増大させるだけでなく、帯域幅リソースの大きな浪費にもつながります。

この問題に対処するために、HTML5 は WebSocket プロトコルを採用しています。これは、クライアントとサーバー間のより効率的な通信を確立します。 WebSocket は、クライアントとサーバー間の同時双方向通信を可能にする全二重通信をサポートしています。 これにより、サーバーはクライアント側のポーリングを必要とせずに、最新のデータをクライアントにプロアクティブにプッシュできます。 不要なリクエストが少ないため、双方向通信によりデータ交換の効率が大幅に向上し、サーバーと帯域幅リソースの消費が削減されると同時に、ユーザーによりスムーズなリアルタイムインタラクションが提供されます。

WebSocket の特性

WebSocket 接続を確立する前に、クライアントとサーバーは 3 ウェイ TCP ハンドシェイクと、ハンドシェイクとも呼ばれる特別な HTTP リクエストを実行して、HTTP 接続を WebSocket 接続にアップグレードする必要があります。 アップグレード中、クライアントとサーバーは HTTP ではなく WebSocket を介して通信します。 双方向通信は、同じ WebSocket 接続を介して確立できます。

WebSocket 接続が確立されると、接続は開いたままになり、双方向通信が可能になります。 WebSocket では、データ交換ごとに新しい接続を必要としたり、応答を待機したりする必要はありません。 WebSocket を介して確立された永続的で低遅延の接続により、データ交換の効率が大幅に向上します。

WebSocket は、データフレームとしてクライアントとサーバー間でデータを交換します。 WebSocket メッセージに必要なヘッダーは小さく、テキストまたはバイナリデータとして交換できます。 このタイプの通信により、永続的な接続のオーバーヘッドが削減され、データ交換の効率が向上します。 高パフォーマンスのリアルタイムインタラクションを提供しながら、サーバーと帯域幅のリソースをあまり必要としません。

WebSocket の詳細については、「The WebSocket Protocol」をご参照ください。

ユースケース

WebSocket は、AI アプリケーション、オンラインチャットルーム、リアルタイム通知システム、多人数参加型オンラインゲーム、リアルタイムメッセージプッシュなど、インスタントまたはリアルタイムの双方向通信を必要とするシナリオに適しています。

ある企業が Alibaba Cloud にオンラインチャットアプリケーションをデプロイしました。 ユーザーはドメイン名にアクセスしてバックエンドサーバーにアクセスできます。バックエンドサーバーでは、ユーザーが相互に対話できます。 アプリケーションは、ユーザー間の低遅延、高効率、双方向、リアルタイムのデータ交換をサポートするために、インスタント通信を必要とします。

高い同時実行性と永続的な接続管理が課題となっています。 ユーザー数が増加するにつれて、従来の HTTP モデルでは、多数のユーザーの同時リアルタイム通信をサポートできなくなります。 データ交換のたびに新しい接続が必要です。 このモデルは、サーバーの負荷を大幅に増加させ、サーバーのパフォーマンスを低下させます。

このシナリオでは、企業は ALB と WebSocket を一緒に使用して永続的な接続を管理し、高い同時実行性を維持できます。 企業は複数のバックエンドサーバーに WebSocket アプリケーションをデプロイし、Redis を使用してメッセージを同期できます。 このソリューションは、サービスの高可用性を確保し、オンラインチャットルームの信頼性が高く、効率的でリアルタイムのメッセージプッシュを可能にします。

使用上の注意

ALB の HTTP リスナーは、デフォルトで WebSocket をサポートしています。 また、ALB はローリングアップデートをサポートしています。 構成の変更は、既存の永続的な接続には影響しません。

ALB を使用する場合は、次の点に注意してください。

  • ALB とバックエンドサーバー間の接続を HTTP/1.1 などの特定のバージョンの HTTP を介して確立する場合、HTTP バージョンをサポートする Web サーバーをバックエンドサーバーとして使用することをお勧めします。

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

    • HTTP リスナーの [接続リクエストのタイムアウト] パラメーターの値を変更して、タイムアウト期間を任意の値に設定できます。

    • 接続を維持するには、キープアライブメカニズムを使用して、60 秒ごとに ALB とバックエンドサーバー間でパケットを交換する必要があります。

前提条件

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

  • 3 つの Elastic Compute Service (ECS) インスタンスが作成されていること。 この例では、ECS インスタンスの名前は ECS01、ECS02、ECS03 です。

    • WebSocket アプリケーションは ECS01 と ECS02 にデプロイされます。 Redis は ECS03 にデプロイされます。

    • この例では、すべての ECS インスタンスで CentOS 7.9 オペレーティングシステムを使用しています。

    • ECS01、ECS02、ECS03 を同じセキュリティグループに追加することをお勧めします。 ECS インスタンスを異なるセキュリティグループに追加する場合は、相互に通信ポートへのアクセスを許可する必要があります。

  • ドメイン名が登録されており、そのドメイン名にインターネットコンテンツプロバイダー (ICP) 番号が取得されていること。 詳細については、「汎用ドメイン名の登録」および「ICP 登録プロセス」をご参照ください。

手順

手順 1: アプリケーションをデプロイする

ECS03 に Redis を、ECS01 と ECS02 に WebSocket アプリケーションをデプロイします。

次の例は、テストオンラインチャットルームをデプロイする方法を示しています。 この例では、ECS インスタンスで CentOS 7.9 オペレーティングシステムを使用しています。 この例は参照用です。 プログラムとアプリケーションの構成を調整してください。

ECS03 に Redis をデプロイする

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

  2. ECS03 で次のコマンドを実行して、Redis をデプロイおよび構成します。

    # Extra Packages for Enterprise Linux (EPEL) をインストールします
    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 が アクティブ (実行中) 状態であると表示されている場合、Redis はデプロイされ、構成が有効になります。次の図に示すように。

    image

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 サーバーの IP アドレス (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!'
    # オリジン間リソース共有 (CORS) を有効にします
    CORS(app)
    
    # キューを管理し、状態を保存するように Redis を構成します
    redis_url = "redis://192.168.*.*:6379/0"  # IP アドレスを 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_id} が接続されました。")
            welcome_message = "チャットルームへようこそ!"
            emit('message', welcome_message)
            set_session_data(session_id, "username", '')  # 初期化されたユーザー名は空です
        except Exception as e:
            print(f"接続中にエラーが発生しました: {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} がチャットルームを退出しました。"
                emit('message', leave_message, broadcast=True)
                print(leave_message)
            delete_session_data(session_id)
            print(f"セッション {session_id} が切断されました。")
        except Exception as e:
            print(f"切断中にエラーが発生しました: {str(e)}")
    
    
    @socketio.on('set_username')
    def handle_set_username(username):
        session_id = request.sid
        set_session_data(session_id, "username", username)
        print(f"クライアント {session_id} のユーザー名を {username} に設定しました")
        emit('message', f"ユーザー名が {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 = "メッセージの送信に失敗しました。最初にユーザー名を指定してください。"
            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>チャットルーム</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>オンラインチャットルーム</h1>
        <div class="chat-container">
            <div class="user-container">
                <input type="text" id="username" autocomplete="off" placeholder="ユーザー名を入力してください">
                <button onclick="setUsername()">ユーザー名として設定</button>
            </div>
            <div id="messages"></div>
            <div class="message-container">
                <input type="text" id="myMessage" autocomplete="off" placeholder="メッセージを入力してください...">
                <button onclick="sendMessage()">送信</button>
            </div>
        </div>
        <script>
            var socket = io({ transports: ['websocket', 'polling', 'flashsocket'] });
            var usernameSet = false;
            socket.on('connect', function() {
                console.log("サーバーに接続しました!");
                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("ユーザー名は空にできません。");
                }
            }
            function sendMessage() {
                if (usernameSet) {
                    var message = $('#myMessage').val();
                    if (message) {
                        socket.send(message);
                        $('#myMessage').val('');
                    } else {
                        alert("メッセージは空にできません。");
                    }
                } else {
                    alert("最初にユーザー名を指定してください。");
                }
            }
        </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)
    

    WebSocket アプリケーションを有効にできない場合は、指定したポートが別のアプリケーションによって使用されているかどうか、またはコマンドやコードにエラーがないかを確認してください。

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 サーバーの IP アドレス (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!'
    # オリジン間リソース共有 (CORS) を有効にします
    CORS(app)
    
    # キューを管理し、状態を保存するように Redis を構成します
    redis_url = "redis://192.168.*.*:6379/0"  # IP アドレスを 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_id} が接続されました。")
            welcome_message = "チャットルームへようこそ!"
            emit('message', welcome_message)
            set_session_data(session_id, "username", '')  # 初期化されたユーザー名は空です
        except Exception as e:
            print(f"接続中にエラーが発生しました: {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} がチャットルームを退出しました。"
                emit('message', leave_message, broadcast=True)
                print(leave_message)
            delete_session_data(session_id)
            print(f"セッション {session_id} が切断されました。")
        except Exception as e:
            print(f"切断中にエラーが発生しました: {str(e)}")
    
    
    @socketio.on('set_username')
    def handle_set_username(username):
        session_id = request.sid
        set_session_data(session_id, "username", username)
        print(f"クライアント {session_id} のユーザー名を {username} に設定しました")
        emit('message', f"ユーザー名が {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 = "メッセージの送信に失敗しました。最初にユーザー名を指定してください。"
            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>チャットルーム</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>オンラインチャットルーム</h1>
        <div class="chat-container">
            <div class="user-container">
                <input type="text" id="username" autocomplete="off" placeholder="ユーザー名を入力してください">
                <button onclick="setUsername()">ユーザー名として設定</button>
            </div>
            <div id="messages"></div>
            <div class="message-container">
                <input type="text" id="myMessage" autocomplete="off" placeholder="メッセージを入力してください...">
                <button onclick="sendMessage()">送信</button>
            </div>
        </div>
        <script>
            var socket = io({ transports: ['websocket', 'polling', 'flashsocket'] });
            var usernameSet = false;
            socket.on('connect', function() {
                console.log("サーバーに接続しました!");
                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("ユーザー名は空にできません。");
                }
            }
            function sendMessage() {
                if (usernameSet) {
                    var message = $('#myMessage').val();
                    if (message) {
                        socket.send(message);
                        $('#myMessage').val('');
                    } else {
                        alert("メッセージは空にできません。");
                    }
                } else {
                    alert("最初にユーザー名を指定してください。");
                }
            }
        </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.p コマンドを実行して、スクリプトを実行します。

  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)
    

    WebSocket アプリケーションを有効にできない場合は、指定したポートが別のアプリケーションによって使用されているかどうか、またはコマンドやコードにエラーがないかを確認してください。

手順 2: サーバーグループを構成する

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

  2. 上部のナビゲーションバーで、ALB インスタンスがデプロイされているリージョンを選択します。

  3. 左側のナビゲーションウィンドウで、[サーバーグループ] をクリックします。

  4. [サーバーグループ] ページで、[サーバーグループの作成] をクリックします。 [サーバーグループの作成] ダイアログボックスで、パラメーターを構成し、[作成] をクリックします。 次の表では、一部のパラメーターのみについて説明します。 ビジネス要件に基づいて他のパラメーターを構成するか、デフォルト値を使用します。

    パラメーター

    説明

    サーバーグループタイプ

    作成するサーバーグループのタイプを選択します。

    VPC

    ECS01 と ECS02 の仮想プライベートクラウド (VPC) を選択します。

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

  5. [サーバーグループが作成されました] メッセージで、[バックエンドサーバーの追加] をクリックします。

  6. [バックエンドサーバーの追加] ウィザードで、ECS01 と ECS02 をバックエンドサーバーとして追加します。 ポートを WebSocket アプリケーションのポートに設定します。 この例では、WebSocket アプリケーションはポート 5000 を使用します。

手順 3: HTTP リスナーを追加する

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

  2. 上部のナビゲーションバーで、ALB インスタンスがデプロイされているリージョンを選択します。

  3. 左側のナビゲーションウィンドウで、[インスタンス] をクリックします。

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

  5. [リスナーの構成] 手順で、パラメーターを構成します。 次の表では、一部のパラメーターのみについて説明します。 ビジネス要件に基づいて他のパラメーターを構成するか、デフォルト値を使用します。 パラメーターを構成した後、[次へ] をクリックします。

    パラメーター

    説明

    リスナープロトコル

    HTTP を選択します。

    リスナーポート

    この例では、ポート 5000 が使用されます。

  6. [サーバーグループの選択] 手順で、パラメーターを構成します。 次の表では、一部のパラメーターのみについて説明します。 ビジネス要件に基づいて他のパラメーターを構成するか、デフォルト値を使用します。 パラメーターを構成した後、[次へ] をクリックします。

    パラメーター

    説明

    サーバーグループ

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

  7. [構成の確認] 手順で、パラメーターが有効かどうかを確認し、[送信] をクリックします。

手順 4: DNS レコードを追加する

実際のビジネスシナリオでは、CNAME レコードを使用してカスタムドメイン名を ALB インスタンスのドメイン名にマッピングすることをお勧めします。

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

  2. [インスタンス] ページで、ALB インスタンスのドメイン名をコピーします。

  3. 次の手順を実行して CNAME レコードを作成します。

    説明

    Alibaba Cloud ドメインを使用してドメイン名を登録していない場合は、DNS レコードを構成する前に、Alibaba Cloud DNS にドメイン名を追加する必要があります。 詳細については、「ドメイン名の管理」をご参照ください。

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

    2. [権限のある DNS 解決] ページで、ドメイン名を見つけ、[DNS 設定][操作] 列の をクリックします。

    3. ドメイン名詳細ページの [DNS 設定] タブで、[DNS レコードの追加] をクリックします。

    4. [DNS レコードの追加] パネルで、パラメーターを構成し、[OK] をクリックします。 次の表にパラメーターを示します。

      パラメーター

      説明

      レコードタイプ

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

      ホスト名

      ドメイン名のプレフィックスを入力します。 この例では、@ と入力します。

      説明

      ルートドメイン名を使用する場合は、@ と入力します。

      DNS リクエストソース

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

      レコード値

      CNAME、つまり ALB インスタンスのドメイン名を入力します。

      TTL 期間

      CNAME レコードが DNS サーバーにキャッシュされる生存時間 (TTL) 値を選択します。 この例では、デフォルト値が使用されます。

手順 5: 結果を確認する

異なる IP アドレスを持ち、インターネットアクセスをサポートする 2 台のコンピューターを準備します。 コンピューターのブラウザからメッセージを送信して、ALB インスタンスが WebSocket メッセージをリアルタイムでプッシュできるかどうかをテストします。

  1. ブラウザから http://ドメイン名:5000 にアクセスして、オンラインチャットルームにアクセスします。

    次の図は、チャットルームにアクセスできることを示しています。

    image

    ブラウザで開発者ツールを開くと、[ネットワーク] タブで WebSocket 通信が確立されていることがわかります。

    image

  2. ユーザー名を入力し、ユーザー名として設定 をクリックします。

  3. メッセージを入力し、[送信] をクリックします。この操作を複数のコンピューターで繰り返します。

    次の図は、異なるコンピューターからのメッセージがブラウザに表示されることを示しています。

    image

  4. 前述のテストは、ALB が高可用性を維持しながら WebSocket メッセージをリアルタイムでプッシュできることを示しています。

FAQ

WebSocket Secure プロトコルはどのように使用しますか?

WebSocket Secure は、WebSocket の暗号化バージョンです。

デフォルトでは、HTTPS リスナーは WebSocket Secure をサポートしています。 WebSocket Secure を有効にするには、HTTPS リスナーを作成します。

WebSocket の使用は課金されますか?

WebSocket または WebSocket Secure の使用に対して課金されることはありません。

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

WebSocket と WebSocket Secure は、ALB のすべてのリージョンでサポートされています。

関連情報

テストを容易にするために、このトピックでは簡単な例を使用して ECS インスタンスに Redis をデプロイする方法を説明しています。 ただし、Redis サーバーエラーにより、単一障害点 (SPOF) が発生する可能性があります。 実稼働環境では、Tair (Redis OSS 互換) とは を使用してアプリケーションの高可用性を向上させることをお勧めします。 詳細については、「概要」をご参照ください。