在ELB后面使用多个实例中的Socket.IO和Redis

4
我在AWS上设置了两个EC2实例,运行在负载均衡器后面,但是当两个实例同时运行时,socket.io会出现问题。我认为这是由于ELB轮询实例和Socket.io在更新到Websockets之前发送请求导致的(会话ID未知)。
我认为通过在Redis上使用共享会话存储,Socket.io可以正常工作,因为所有实例都可以访问会话。
我有一个小应用程序,是使用Node.js(更具体地说是Sails.js)开发的,只是用于测试。我成功配置了ELB以支持TCP模式下的Websockets,并将请求转发到(Phusion Passenger + NGINX),该应用程序运行在Sails.js上。
该应用程序使用运行在Amazon Elasticache上的Redis进行SESSIONS和SOCKETS。如果我单独测试两个实例而没有使用ELB,则可以看到Redis对Sockets有效,因为消息可以在两个实例中发送和接收。
共享会话是否足以使Socket.io正常工作?还是我需要在ELB中使用粘性会话将客户端转发到相同的实例?
我选择ELB是因为它更容易动态添加和删除实例,而使用NGINX(免费版)或HAProxy则比较复杂。
有什么想法吗?

我有同样的问题。你是如何解决这个问题的?你使用socket.io-redis吗? - Grégoire Motot
@grégoire-motot,最终我使用了仅限于Websockets的socket.io和socket-io-redis。要使用其他传输方式,如XHR轮询或JSONP轮询,您需要具有粘性会话。您可能会发现这篇文章很有用在EC2上负载均衡Websockets - Lucas Lima
1个回答

0

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

Socket.io、SockJS和类似库所具有的约束之一是它们需要不断地与服务器的同一实例进行通信。当只有一个服务器实例时,它们可以完美地工作。

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

为了帮助解决这种情况,负载均衡器具有称为“粘性会话”或“会话亲和力”的功能。其主要思想是,如果设置了此属性,则在第一个负载平衡请求之后,所有后续请求都将发送到同一服务器实例。

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

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

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

app.use(cookieParser); app.use(express.session({store:sessionStore, key:'jsessionid', secret:'your secret here'}));

这些是步骤:

  1. Express设置一个名为jsessionid的会话cookie。
  2. 当socket.io连接时,它使用相同的cookie并命中负载均衡器。
  3. 负载均衡器始终将其路由到设置cookie的同一台服务器。
  4. 如果您正在使用应用程序负载均衡器,则粘性会话设置位于目标组级别。

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