16

我计划在 EC2 上设置一组运行Socket.io的 NodeJS 应用程序服务器,并且我想使用弹性负载均衡器在它们之间分散负载。我知道 ELB 不支持开箱即用的 Websocket,但我可以使用Scenario 2 中描述的设置。

但是,如博客文章中所述,我注意到此设置不提供会话关联或源 IP 信息:

我们不能在此设置中使用 Session Affinity 或 X-Forward 标头,因为 ELB 不解析 HTTP 消息,因此无法匹配 cookie 以确保 Session Affinity 或注入特殊的 X-Forward 标头。

Socket.io 在这些情况下还能工作吗?或者是否有另一种方法可以在具有 SSL 的负载均衡器后面拥有一组 Socket.io 应用程序服务器?

编辑:Tim Caswell 已经在这里谈论过这样做。有没有解释如何设置的帖子?这里再次没有会话粘性,但事情似乎运行良好。

顺便说一句,websockets 真的需要粘性会话吗?信息是作为新的和单独的请求传播的,还是只有一个请求+连接所有信息都在传播?

4

4 回答 4

15

即使使用 TCP ELB,Socket.io 也无法开箱即用,因为它会在升级到 websocket 的连接之前发出两个 HTTP 请求。

第一个连接用于建立协议,因为 socket.io 不仅支持 websockets。

GET /socket.io/1/?t=1360136617252 HTTP/1.1
User-Agent: node-XMLHttpRequest
Accept: */*
Host: localhost:9999
Connection: keep-alive

HTTP/1.1 200 OK
Content-Type: text/plain
Date: Wed, 06 Feb 2013 07:43:37 GMT
Connection: keep-alive
Transfer-Encoding: chunked

47
xX_HbcG1DN_nufWddblv:60:60:websocket,htmlfile,xhr-polling,jsonp-polling
0

第二个请求用于实际升级连接:

GET /socket.io/1/websocket/xX_HbcG1DN_nufWddblv HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: MTMtMTM2MDEzNjYxNzMxOA==
Host: localhost:9999

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 249I3zzVp0SzEn0Te2RLp0iS/z0=

您可以在上面的示例中看到,这xX_HbcG1DN_nufWddblv是请求之间的共享密钥。这就是问题。ELB 执行循环路由,这意味着升级请求会到达未参与初始协商的服务器。因此,服务器不知道客户端是谁。

内存中的状态数据是负载均衡的敌人。值得庆幸的是,socket.io 支持使用 Redis 来存储数据。如果您与多个服务器共享您的 redis 连接,它们实质上共享所有客户端的会话。

有关设置 Redis 的详细信息,请参阅socket.io wiki 页面。

于 2013-02-06T18:27:44.520 回答
14

您现在可以使用 AWS 最近推出的新应用程序负载均衡器。

只需将 ELB(现在称为经典负载均衡器)替换为 ALB(应用程序负载均衡器)并启用粘性会话。

ALB 支持 Web 套接字。这应该可以解决问题。

https://aws.amazon.com/blogs/aws/new-aws-application-load-balancer/

http://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html

于 2016-08-18T08:00:44.153 回答
5

正如我在帖子中提到的,我们只使用 ELB 来在支持 websocket 的 http-proxy 服务器集群之间进行 ssl 终止和负载平衡。ELB 不直接与 websocket 服务器对话。HTTP 代理集群负责查找正确的 socket.io 服务器以连接以确保会话粘性。

于 2012-11-14T15:42:43.970 回答
-1

当您在具有负载平衡器/反向代理、路由器等的云中运行服务器时,您需要对其进行配置以使其正常工作,尤其是当您扩展服务器以使用多个实例时。

Socket.io、SockJS 和类似库的限制之一是它们需要不断地与服务器的同一个实例通信。当只有一个服务器实例时,它们工作得很好。

当您在云环境中扩展您的应用程序时,负载均衡器(在 Cloud Foundry 的情况下为 Nginx)将接管,请求将被发送到不同的实例,从而导致 Socket.io 中断。

为了在这种情况下提供帮助,负载均衡器具有称为“粘性会话”又名“会话亲和性”的功能。主要思想是,如果设置了这个属性,那么在第一个负载均衡请求之后,后面的所有请求都会去同一个服务器实例。

在 Cloud Foundry 中,为设置 cookie jsessionid 的应用程序启用了基于 cookie 的粘性会话。

注意:jsessionid 是 Java/Spring 应用程序中通常用于跟踪会话的 cookie 名称。Cloud Foundry 只是采用它作为所有框架的粘性会话 cookie。

因此,所有应用程序需要做的就是设置一个名为 jsessionid 的 cookie 以使 socket.io 工作。

app.use(cookieParser); app.use(express.session({store:sessionStore, key:'jsessionid', secret:'你的秘密'}));

所以这些是步骤:

Express 设置一个名为 jsessionid 的会话 cookie。当 socket.io 连接时,它使用相同的 cookie 并命中负载均衡器负载均衡器始终将其路由到设置 cookie 的同一服务器。如果您使用的是 Application Load Balancer,则粘性会话设置处于目标组级别

于 2017-01-15T06:19:16.460 回答