应用程序负载均衡器是不是支持 WebSockets?

Posted

技术标签:

【中文标题】应用程序负载均衡器是不是支持 WebSockets?【英文标题】:Does an Application Load Balancer support WebSockets?应用程序负载均衡器是否支持 WebSockets? 【发布时间】:2017-01-13 03:29:36 【问题描述】:

我有一个最初配置为使用 Classic Load Balancer 的 Elastic Beanstalk 应用程序。我发现这在通过 WebSocket 连接时会导致错误。因此,我将应用程序配置为使用 Application Load Balancer,因为有人告诉我 ALB 支持 WebSockets。但是,它们似乎没有:尝试通过 WebSocket 连接到我的 ALB 时遇到完全相同的错误。

ALB 真的支持 WebSocket 吗? AWS 文档在这方面是矛盾的。 This page 说它只支持 HTTP 和 HTTPS。没有设置 ALB 以支持 WebSocket 的指南。

【问题讨论】:

来自官方博客:aws.amazon.com/blogs/aws/new-aws-application-load-balancer "ALB 通过 ws:// 和 wss:// 协议为 WebSocket 提供原生支持。" 尽管有 ALB 的公告和常见问题解答部分,但我在 ALB 上也遇到了同样的错误(http 状态 501 未实现) 尽管aws.amazon.com/elasticloadbalancing/applicationloadbalancer/… Socket.io 有问题,似乎不能开箱即用。 【参考方案1】:

我能够让 WebSockets 与新的 Application Load Balancer (ALB) 一起使用。

首先,为您的 ALB 创建一个新的目标组。此目标组应使用与您的应用程序相同的端口,并且需要配置运行状况检查。但是,主要区别在于您必须启用粘性。

接下来,将新的侦听器规则添加到您的 ALB。此规则必须有一个路径来路由 WebSocket 设置 -- /socket.io。另外,将 Target Group Name 设置为您刚刚创建的 Target Group。

我正在为我的服务器使用 Node/Hapi/Socket.io(在派生自 Amazon Linux AMI 的实例上运行)。基本设置是:

const hapi = require('hapi');
const websocket = require('./WebSocket');

var server = new hapi.Server();
server.connection(config.Application);
websocket.Initialize(server.listener);

WebSocket.js 在哪里

var io = null;

module.exports = 

    Initialize: function (http) 

        io = require('socket.io')(http);

        io.on('connection', function (socket) 
            console.log('Websocket ' + socket.id + ' connected.');

            socket.on('disconnect', function () 
                console.log('Websocket ' + socket.id + ' disconnected.');
            );
        );
    
;

我正在为我的客户端使用 Angular 1.5x,带有 socket.io-client。请务必按如下方式配置 WebSocket 客户端选项,否则您将无法连接。

(function () 

    'use strict';

    angular
        .module('XXXXX', [])
        .run(runHandler);

    runHandler.$inject = ['WebSocketService'];

    function runHandler(WebSocketService) 
       WebSocketService.Initialize();
    
)();

WebSocket 服务:

(function () 

    'use strict';

    angular
        .module('XXXXX')
        .factory('WebSocketService', WebSocketService);

    WebSocketService.$inject = [];

    function WebSocketService() 

        var socket = null;

        function initialize() 

            var url = 'http://' + ALB_URL + ':5800';

            socket = io(url, transports: ['websocket'], upgrade: false);

            socket.on('connect', function () 
                console.log('Socket connected');
            );

            socket.on('disconnect', function () 
                console.log('Socket disconnected');
            );
        

        return 
            Initialize: initialize
        ;
    
)();

【讨论】:

您的健康检查配置是什么? socket.io 或您的应用程序代码是否有特殊的健康检查端点?在我的情况下,请求 / 会导致 HTTP 426 响应,ALB 认为它不健康。 我在 ALB 后面有两个 VM。每个都托管一个 Node Web 服务。我在 http::5800/v1/monitor/ping 有一个 REST 端点,它以 HTTP 200 OK 的字符串形式返回当前服务器日期/时间。我在我的 API(非 Web 套接字)Target Group->Health Checks 中配置此信息。 @programmerj 那么你的 ALB_URL 是什么? “xxx.us-east-1.elasticbeanstalk.com/socket.io:5800”?它要求路径完全是“socket.io”还是任意的? Flask-socketio 通过端口 5000 暴露 websocket,所以我会使用端口 5000 吗? 你好@Alpenglow。从内存中删除,因为我不再使用此堆栈,但 ALB_URL 将是应用程序负载均衡器的生成 URL,或者在我的情况下,是在 Route53 中创建的指向应用程序负载均衡器的 URL。只要客户端匹配,我认为路径不必是“socket.io”。我相信你会在你的情况下使用 5000。 感谢这篇文章。但是,有没有人遇到过套接字断开然后重试的问题?它似乎保持连接一段时间,然后间歇性地失去连接。我注意到它给出了“WebSocket 握手期间出错:意外的响应代码:502” - 有什么想法吗?【参考方案2】:

ALB 支持 Websocket,但如果实例至少每隔“空闲超时”秒发送一些数据,负载均衡器可以关闭连接。

【讨论】:

【参考方案3】:

应用负载均衡器支持 websocket。但是直到 2017 年 2 月 23 日才支持 websocket 健康检查。他们可能会在以后添加一个选项。当您想在 Application Load Balancer 后面使用 websocket 时,您需要为目标组设置 HTTP 或 HTTPS 运行状况检查。

来自 AWS 文档: “请注意,健康检查不支持 WebSockets。”

参考:http://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html

【讨论】:

请注意,我们在 2018 年,接近 2019 年,AWS 仍然不支持 WSS 健康检查:'(docs.aws.amazon.com/elasticloadbalancing/latest/application/… 仍然说【参考方案4】:

ALB(应用程序负载平衡器)支持 websocket。你可以在这里查看https://aws.amazon.com/blogs/aws/new-aws-application-load-balancer/enter image description here

ALB 也会根据配置的空闲超时关闭连接。

SnapShot from the above blog

【讨论】:

这实际上没有帮助。【参考方案5】:

就nodejs而言 当我们在客户端使用 socket io 并调用 socket.js 库时 像这样

const socket = io('domain.com');

我观察到的是,当我将 Http 指定为协议时,它会将调用重定向到 ws://domain.com 但是当我指定 https 时,它会重定向到 wss://domain.com 并且我收到此错误失败: WebSocket 握手期间出错:意外的响应代码:400 我所做的是我指定了

const socket = io(window.location.origin, reconnect: true,transports: ['websocket']);

确实解决了我的问题

【讨论】:

以上是关于应用程序负载均衡器是不是支持 WebSockets?的主要内容,如果未能解决你的问题,请参考以下文章

WebSockets 和 HTTPS 负载均衡器

spark-cassandra-connector 是不是支持内置负载均衡?

如何设置我的 Elastic Beanstalk 应用程序以使用 Application Load Balancer?

在 AWS Elastic Load Balancer 后面使用 Primus.io (websockets)

Spring WebSockets ActiveMQ convertAndSendToUser

Elastic Beanstalk 在配置菜单中没有负载均衡器设置