使用TCP负载均衡器代理WebSockets而无需粘性会话

40
我想使用Amazon Elastic Load Balancer代理WebSocket连接到多个node.js服务器。由于Amazon ELB不提供实际的WebSocket支持,因此我需要使用其原始TCP消息传递功能。但是,我正在尝试了解如何在没有某种粘性会话功能的情况下使其正常工作。
我知道WebSocket的工作原理是首先由客户端发送HTTP Upgrade请求,服务器通过发送正确处理密钥身份验证的响应来处理该请求。在服务器发送响应并得到客户端批准后,该客户端和服务器之间建立了双向连接。
然而,假设客户端在批准服务器响应后向服务器发送数据。如果它将数据发送到负载均衡器,并且负载均衡器将该数据中继到未处理原始WebSocket Upgrade请求的其他服务器,那么这个新服务器将如何知道WebSocket连接?或者客户端是否会自动绕过负载均衡器并直接将数据发送到处理初始升级的服务器?
2个回答

68
我认为我们需要了解整个WebSocket创建过程中底层TCP连接的演变方式,才能回答这个问题。你会发现,WebSocket连接中的“粘性”部分就是底层TCP连接本身。我不确定在WebSocket上下文中,“会话”是什么意思。
从高层次来看,初始化“WebSocket连接”需要客户端向HTTP服务器发送HTTP GET请求,请求包括“Upgrade”标题字段。现在,对于此请求的发生,客户端需要与HTTP服务器建立TCP连接(这可能是显而易见的,但我认为在这里明确指出这一点非常重要)。随后的HTTP服务器响应将通过相同的TCP连接发送。
请注意,现在,在服务器响应已发送之后,如果未被客户端或服务器主动关闭,则TCP连接仍然处于打开/活动状态。
现在,根据WebSocket标准RFC 6455,在第4.1节 的结尾处:

如果服务器的响应按上述方式验证,则可以说WebSocket连接已经建立,并且WebSocket连接处于打开状态

我从这里读到,由客户端在发送初始HTTP GET(升级)请求之前启动的同一TCP连接将保持打开状态,并且从现在开始将用作全双工WebSocket连接的传输层。这是有道理的!
关于你的问题,这意味着负载均衡器只会在初始HTTP GET(Upgrade)请求之前发挥作用,即在涉及两个通信端点之间建立的唯一TCP连接之前。此后,TCP连接保持建立状态,不能被网络设备“重定向”。我们可以总结出,在您的会话术语中,“TCP连接定义了会话”。只要WebSocket连接处于活动状态(即未终止),它“根据定义”提供并存在于自己的会话中。没有什么可以改变这个会话。在这种情况下,两个独立的WebSocket连接不能共享相同的会话。如果您使用“Session”指的是其他内容,那么可能是应用程序层引入的会话,我们无法对其进行评论。
编辑后: 引用您的评论:“所以你的意思是负载均衡器不涉及TCP连接?” 不,至少通常情况下不是这样的。它确实可以影响TCP连接的建立,因为它可以决定如何处理客户端连接尝试。具体取决于负载均衡器的确切类型(*请参见下文)。重要的是,在两个端点之间建立连接后--我不认为负载均衡器是一个端点,我指的是WebSocket客户端和WebSocket服务器--这两个端点将不再更改 WebSocket连接的生命周期。负载均衡器可能仍然位于网络路径中,但可以假定不再产生影响。 引用您的评论:“因此,全双工连接是在客户端和最终服务器之间建立的吗?” 是的! ***有不同类型的负载平衡。根据类型,连接两个端点后负载平衡器的角色是不同的。例如: 如果基于DNS进行负载均衡,则负载均衡器在最终TCP连接方面根本没有参与。它只是直接告诉客户端要连接哪个主机。
  • 如果负载均衡器的工作方式类似于AWS的Layer 4 ELB(文档在这里),那么它就像代理TCP连接一样工作。因此,客户端实际上会将ELB本身视为服务器。然而,发生的事情是,ELB只是在不改变任何内容的情况下将数据包双向转发。因此,它仍然严重涉及TCP连接,只是透明地进行。在这种情况下,实际上有两个永久的TCP连接:一个从您到ELB,一个从ELB到服务器。对于WebSocket连接的整个生命周期,这些连接都是永久性的。

  • 好的,我会用其他措辞尝试一下 :-) 1)AWS第4层ELB将传入的TCP连接代理到其选择的后端服务器。 2)从此刻开始,在此TCP连接的生命周期内,* ELB维护客户端和后端服务器之间的准直接连接*。 3)“准直接”意味着连接通过ELB进行代理。因此,在TCP连接处于活动状态时,ELB完全了解参与的两个端点(客户端和后端服务器)。 - Dr. Jan-Philip Gehrcke
    4
    你可能需要明白有状态和无状态协议之间的区别。虽然HTTP本身是一个无状态协议,但你的问题非常有意义——对于通常独立的HTTP请求进行负载均衡是一项挑战。在HTTP的情况下,保持一个客户端和一个后端服务器之间的对应关系需要使用技巧。而TCP连接是有状态和永久的,因此在TCP连接的情况下,客户端和后端服务器之间的对应关系已经符合定义。如果这个原则被违反了,那么它就不再是TCP连接了。 - Dr. Jan-Philip Gehrcke
    2
    广告1)“有状态”和“无状态”是适用于许多情况的概念。您可以阅读很多相关内容。关于协议,您可以从这里开始:http://en.wikipedia.org/wiki/Stateless_protocol -- 广告2)ELB必须实现一种机制,直接连接客户端<-->ELB和ELB<-->后端。为简单起见,您可以将其视为查找表。 - Dr. Jan-Philip Gehrcke
    在这里提出一点,以防被忽略。一旦握手完成,TCP连接将保持活动状态,AWS ELB就不是问题了。然而,在协商过程中会发出两个请求,如果第二个请求没有路由到相同的端点,则协商将失败。 - Jake Hoffner
    嘿,杰克。你能否添加一个关于“在谈判过程中进行两个请求”的确切含义的参考吗? - Dr. Jan-Philip Gehrcke
    显示剩余8条评论

    7
    WebSocket使用持久的TCP连接,因此需要将该TCP连接的所有IP数据包转发到同一后端服务器(在TCP连接的生命周期内)。
    它需要具有粘性。这与L7 HTTP负载平衡器不同,后者能够按每个HTTP请求进行调度。
    负载均衡器可以通过不同的方法实现粘性,例如:
    • 将源IP /端口哈希到活动后端服务器集合
    • 在建立TCP连接时,选择一个后端服务器并记住它

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