Azure 上的 SignalR 连接与负载均衡器

Posted

技术标签:

【中文标题】Azure 上的 SignalR 连接与负载均衡器【英文标题】:SignalR connections on Azure with load balancer 【发布时间】:2017-01-20 20:34:26 【问题描述】:

我在 Azure 资源管理器中有下一个设置:

1 个规模集,包含 2 个具有 Windows Server 2012 的虚拟机。 1 Azure Redis 缓存(C1 标准) 1 Azure 负载均衡器(OSI 网络参考堆栈中的第 4 层) 负载均衡器基本上是使用 :https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-get-started-internet-portal 配置的 .规则的会话持久性设置为无。

在规模集的两个 VM 上,我部署了一个测试 Web 应用,它在 .Net 4.5.2 上使用 SignalR 2。 测试 Web 应用使用 Azure Redis 缓存作为背板。 Web 应用项目可以在 github 上找到:https://github.com/gaclaudiu/SignalrChat-master。

在测试期间,我确实注意到在打开信号器连接后,从客户端发送的所有数据,在下一个请求中,都从规模集到达同一服务器,在我看来,SignalR 连接知道哪个从规模出发。

我很想知道更多关于它是如何工作的,我试图在互联网上做一些研究,但在这一点上找不到明确的东西。

我也很想知道下一个案例会发生什么: 客户端 1 有一个 Signalr 打开到服务器 A 的连接。 来自客户端 1 的下一个请求通过 SignalR 发送到服务器 B。

这会导致错误吗? 或者客户端只会被通知没有打开连接并尝试打开一个新连接?

【问题讨论】:

【参考方案1】:

嗯,我很惊讶它完全有效。问题是:信号器执行多个请求,直到连接启动并运行。不能保证所有请求都发送到同一个 VM。特别是如果没有启用会话持久性。我有一个类似的问题。您可以在负载均衡器中激活会话持久性,但正如您指出的那样,在 OSI 第 4 层上执行操作将使用客户端 IP 执行此操作(想象来自同一办公室的所有人员使用相同的 IP 访问您的 API)。在我们的项目中,我们使用 Azure 应用程序网关,它与 cookie 关联 -> OSI 应用程序层一起使用。到目前为止,它似乎按预期工作。

【讨论】:

【参考方案2】:

我认为您误解了负载平衡器的工作原理。每个 TCP 连接都必须将其所有数据包发送到相同的目标 VM 和端口。如果在发送了几个数据包后,TCP 连接突然将其余数据包发送到另一个 VM 和/或端口,则 TCP 连接将无法工作。因此,负载均衡器会在 TCP 连接建立时对 TCP 连接的目的地做出一次决定,而且只有一次。一旦建立 TCP 连接,它的所有数据包都会在连接期间发送到相同的目标 IP/端口。我认为您假设来自同一 TCP 连接的不同数据包最终会在不同的 VM 上结束,但事实并非如此。

因此,当您的客户端创建 WebSocket 连接时,会发生以下情况。负载均衡器接收到 TCP 连接的传入请求。它根据分发模式决定将请求发送到哪个目标 VM。它在内部记录此信息。该 TCP 连接的任何后续传入数据包都会自动发送到同一 VM,因为它会从该内部表中查找适当的 VM。因此,您的 WebSocket 上的所有客户端消息都将在相同的 VM 和端口上结束。

如果您创建一个新的 WebSocket,它可能会在不同的 VM 上结束,但来自客户端的所有消息都将在同一个不同的 VM 上结束。

希望对您有所帮助。

【讨论】:

【参考方案3】:

您需要在 Azure 负载均衡器上配置会话持久性。这将确保当客户端请求被定向到服务器 A 时,来自该客户端的任何后续请求都将转到服务器 A。

会话持久性指定来自客户端的流量应在会话期间由后端池中的同一虚拟机处理。 “无”指定来自同一客户端的连续请求可以由任何虚拟机处理。 “客户端 IP”指定来自同一客户端 IP 地址的连续请求将由同一虚拟机处理。 “客户端 IP 和协议”指定来自相同客户端 IP 地址和协议组合的连续请求将由同一虚拟机处理。

【讨论】:

【参考方案4】:

SignalR 只知道您在启动连接时提供的 url,并使用它向服务器发送请求。我相信 Azure App Service 默认使用粘性会话。你可以在这里找到一些细节:https://azure.microsoft.com/en-us/blog/azure-load-balancer-new-distribution-mode/ 当使用多个服务器和横向扩展时,客户端可以向任何服务器发送消息。

【讨论】:

我认为默认没有粘性会话 @Helikaon 你是对的。负载均衡器默认关闭。但是,默认情况下它会为 Azure Web 应用程序打开。 我假设是 Azure Web Apps (AppServices)。我会更新答案。【参考方案5】:

谢谢你们的回答。 稍微阅读一下,似乎 azure 负载均衡器默认使用 5-touple 分布。 这是文章https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-distribution-mode 5-touple 的问题是每个传输会话都是粘性的。 而且我认为这导致使用信号器的客户端请求在规模集中达到相同的 Vm。我认为平衡器将信号器连接解释为单个传输会话。

应用程序网关从一开始就不是一个选项,因为它有许多我们不需要的功能(因此为我们不使用的东西付费是没有意义的)。

但现在看来,应用程序网关是 azure 中唯一能够在平衡流量时进行循环的平衡器。

【讨论】:

如果您想要按 HTTP 请求进行负载平衡,是的,您需要一个代理类型的负载平衡器,如应用程序网关或其他解决方案,因为 SignalIR(如其他 HTTP/1.1 传输)使用持久连接。您需要一个负载均衡器来接收传入的 HTTP 请求,将它们排队,然后根据每个请求将它们传送到后端。 我只是想理解这一点,因为我已经部署了一个使用信号器的应用程序,我们有该应用程序在负载平衡器后面的 2 个虚拟机上运行,​​这将不起作用还是存在关联设置工作吗?

以上是关于Azure 上的 SignalR 连接与负载均衡器的主要内容,如果未能解决你的问题,请参考以下文章

SignalR集群采用Nginx进行负载均衡后连接失败

如何测试托管在 Azure Appservice 上的 SignalR 应用程序(负载 + 功能组合)

signalR的集群与负载均衡

C# BS消息推送 负载均衡-SignalR&Redis的配置

SignalR负载均衡配置要点

Azure Linux VM配置负载平衡后无法连接