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

45
我有一个 Elastic Beanstalk 应用程序,最初配置为使用经典负载均衡器。我发现这会在通过 WebSocket 连接时导致错误。因此,我将应用程序配置为使用应用程序负载均衡器,因为有人告诉我 ALB 支持 WebSocket。然而,似乎它们并不支持:当尝试通过 WebSocket 连接到我的 ALB 时,我得到完全相同的错误。
ALB 是否真正支持 WebSocket?AWS 文档对此存在矛盾。此页面 表示它仅支持 HTTP 和 HTTPS。没有关于设置 ALB 支持 WebSocket 的指南。

从官方博客:https://aws.amazon.com/blogs/aws/new-aws-application-load-balancer/ "ALB通过ws://和wss://协议提供原生支持WebSocket。" - Mark B
尽管有关ALB的公告和FAQ部分,我在一个ALB上仍然遇到了相同的错误(http状态501未实现)。 - nont
不管 https://aws.amazon.com/elasticloadbalancing/applicationloadbalancer/faqs/ - nont
Socket.io存在问题,似乎不能直接使用。 - coolboyjules
5个回答

53

我成功地使用新的应用程序负载均衡器(ALB)实现了WebSockets。

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

Add Target Group with Stickiness

接下来,向您的ALB添加一个新的侦听器规则。此规则必须具有路径以路由WebSocket设置 - /socket.io。同时,将目标组名称设置为您刚刚创建的目标组。

Add Listen rule for WebSocket

我正在使用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
        };
    }
})();

2
你的健康检查配置是什么?socket.io或者你的应用代码有特殊的健康检查端点吗?在我的情况下,请求“/”会导致HTTP 426响应,这被ALB认为不健康。 - dskrvk
1
我在ALB后面有两个虚拟机,每个都托管了一个Node Web服务。我在http:<server>:5800/v1/monitor/ping上有一个REST端点,它将当前服务器日期/时间作为字符串返回,HTTP 200 OK。我在我的API(非Web套接字)目标组->健康检查中配置了这些信息。 - programmerj
@programmerj,你的 ALB_URL 是什么?是不是需要路径正好为 "socket.io",还是随意?Flask-socketio 通过端口5000公开websocket,那么我要使用端口5000吗? - Alpenglow
我只能通过启用负载均衡粘性来使其工作,尽管AWS文档表明这并不是必需的:http://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#sticky-sessions - n4cer500
1
谢谢您发布这篇文章。不过,有人遇到过套接字断开连接然后重试的问题吗?看起来它会保持连接一段时间,然后间歇性地失去连接。我注意到它会出现“WebSocket握手期间发生错误:意外响应代码:502”的错误消息 - 有什么想法吗? - Aaron
显示剩余5条评论

7

ALB可以支持Websocket,但是如果实例在"空闲超时"秒内没有发送任何数据,负载均衡器会关闭连接。


3

6
提醒一下,现在是2018年接近2019年,AWS仍不支持WSS健康检查,文档https://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html仍然如此。 - Cyril Duchon-Doris
9
提醒一下,现在是2022年,AWS仍然不支持WebSocket健康检查,文档链接:https://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html。 :( - jenovachild

1

3
这实际上没有帮助。 - coolboyjules
@coolboyjules 为什么不呢?这是一个指向博客公告 ALB 的链接,其中明确提到它支持 WebSockets,并直接回答了 OP 的问题。 - J. Doe
@coolboyjules 为什么不呢?这是一个指向 ALB 博客公告的链接,其中明确提到它支持 WebSockets,直接回答了 OP 的问题。 - undefined
它是支持的,但具体来说,我们需要采取哪些步骤呢?如何配置它?博客上没有提到任何相关信息,这样就没用了。 - Faizan Akram Dar

-4

关于Node.js 当我们在客户端使用Socket.io并调用socket.js库时, 就像这样

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

我观察到的是,当我指定协议为Http时,它将调用重定向到ws://domain.com,但当我指定https时,它将重定向到wss://domain.com,并且我遇到了这个错误:failed: Error during WebSocket handshake: Unexpected response code: 400。我的做法是指定了


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

确实解决了我的问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接