WebSocket负载均衡实现

WebSocket负载均衡实现

优化资源使用、最大化吞吐量、最小化响应时间并避免任何单个资源的过载.

负载均衡 大并发 WebSocket 物联网

 

WebSocket负载均衡实现

优化资源使用、最大化吞吐量、最小化响应时间并避免任何单个资源的过载.

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。它允许服务器主动向客户端推送信息,客户端和服务器之间的连接持久化,使得双方可以实现实时的数据传输。WebSocket广泛应用于需要实时通信的应用场景,如在线聊天、实时通知、游戏等。

负载均衡技术可以将客户端的请求分发到多个服务器上,从而平衡服务器的负载,提高系统的整体性能和可靠性。常见的WebSocket负载均衡算法包括:

  • 轮询(Round Robin):按顺序将请求分配给各个服务器,确保每台服务器都能处理一定数量的请求。

  • 加权轮询(Weighted Round Robin):在轮询的基础上,根据服务器的性能或负载情况设置权重,将请求优先分配给性能较好或负载较低的服务器。

  • 最小连接数(Least Connections):将请求分配给当前连接数最少的服务器,以确保所有服务器上的连接数尽可能平衡。

  • 哈希算法(Hashing):根据请求的特定属性(如IP地址、用户ID等)计算哈希值,将相同哈希值的请求分配给同一台服务器,以实现请求的精准分发。

在管理大型系统时,负载均衡问题一直是一个热门问题。负载均衡旨在优化资源使用、最大化吞吐量、最小化响应时间并避免任何单个资源的过载,因此解决此问题对于性能至关重要。在本文中,我们将了解该问题的可能解决方案。

为了更好地理解 WS 负载平衡,让我们更深入地了解 TCP 套接字的背景。默认情况下,单个服务器可以处理 65,536 个套接字连接,因为它是可用 TCP 端口的最大数量。因此,由于 WS 连接具有 TCP 性质,并且每个 WS 客户端都占用一个端口,因此我们可以肯定地说 websocket 连接的数量也是有限的。

实际上,这只是半真半假。服务器可以处理每个 IP 地址的 65,536 个套接字。因此,可以通过向服务器添加额外的网络接口来轻松扩展数量。同时,跟踪服务器上存在的连接数量非常重要。

一旦超过限制,其他 TCP 连接可能会遇到很多问题(例如,无法通过 ssh 连接到服务器)。因此,在应用程序代码中限制每个节点的 WS 连接是一个好主意。当我们处理 websockets 时,我们在应用程序中做同样的事情。

一旦我们了解了主要限制和克服它的方法,我们就可以继续进行负载均衡。下面我将描述我们在其中一个项目中尝试的 3 种方法。请注意,所有系统部件都已部署到 AWS,一些提示和提示仅适用于 Amazon 配置。设计WebSocket负载均衡方案时,可以考虑以下几个方面:

  • 选择合适的负载均衡器:根据实际需求选择合适的负载均衡器,如Nginx、HAProxy等,它们支持WebSocket协议并提供丰富的负载均衡策略。

  • 配置粘性会话:在负载均衡器中配置粘性会话,以确保同一客户端的WebSocket连接在多次请求中始终被分发到同一台服务器上。

  • 监控和日志:配置监控和日志系统,以便实时监控服务器的负载情况和WebSocket连接的状态,及时发现并解决问题。

  • 故障恢复机制:设计故障恢复机制,以便在服务器发生故障时能够自动将连接和消息流量转移到其他服务器上,保证系统的持续运行。

ELB方案

实施负载均衡的最简单方法是使用 AWS 提供的 Elastic Load Balancer。可以将 ELB 切换到 TCP 模式,从而实现任何类型的 TCP 连接的负载均衡,包括 websockets。这种方法提供:

  • LB 的自动故障转移

  • 负载均衡节点的自动扩展

  • 设置非常简单

基本上,对于大多数常见情况,这是一个很好的解决方案,直到您的负载出现飞溅增长。在这种情况下,ELB 变得太慢,无法建立新连接。可以联系 Amazon 并要求他们“预热”ELB,但当我们需要快速建立数千个 WS 连接时,出于负载测试目的,而对于我们的客户来说,由于系统的可用性,这对我们来说不是一个选择。

软件负载均衡器

我们已经尝试将 HAProxy 作为负载均衡器。但是要使 HAProxy 正常工作,应该记住我们上面讨论的端口限制问题。要使 HAProxy 处理超过 65k 个连接,我们应该完成以下步骤:

1. 创建一堆私有 IP 地址。为此,请选择您的 Amazon 实例 -> 操作 -> 联网 -> 管理私有 IP 地址。即添加了 3 个 IP 地址:192.168.1.1、192.168.1.2、192.168.1.3。请记住,IP 应该与你的真实应用程序服务器位于同一子网中;

2. 通过 SSH 连接到您的 HAProxy 实例并运行以下命令:

$> ifconfig eth0:1 192.168.1.1

$> ifconfig eth0:2 192.168.1.2

$> ifconfig eth0:3 192.168.1.3

这将向实例添加 3 个虚拟网络接口;

3. 配置 HAProxy。以下是文件中接受 WS 连接的 3 个 Erlang 节点的部分。haproxy.cfg

listen erlang_front :8888

        mode            http

        balance         roundrobin

        timeout connect 1s

        timeout queue 5s

        timeout server 3600s

        option httpclose

        option forwardfor

        server          erlang-1 192.168.0.1:8888  source 192.168.1.1

        server          erlang-2 192.168.0.2:8888  source 192.168.1.2

        server          erlang-3 192.168.0.3:8888  source 192.168.1.3

现在 HAProxy 可以处理超过 65,536 个 websocket 连接,并且可以通过添加虚拟网络接口轻松增加连接限制。此外,它可以相当快速地建立新的连接。

尽管存在以下缺点,但这种方法似乎是可行的:

  • 故障转移 HAProxy 实例应使用以下工具手动设置keepalived;

  • 每当添加新的 Erlang 节点时,都必须做一些事情来重新配置 HAProxy;

  • 随着连接数量的增加,没有选项可以水平扩展 HAProxy。我们只有垂直选项可用,因此当我们有越来越多的活跃用户时,我们应该为 HAProxy(和 HAProxy 镜像节点)获得越来越昂贵的实例。

我们对这些缺点没问题,但实施了更简单的解决方案。这是可能的,因为我们已经实现了一些代码,并且我们的系统设计允许我们使用自定义方法。

自定义方案

为了继续前进,让我们回顾一下以下显示系统架构的图表。

我们有一个 JavaScript 客户端应用程序、一个负责用户授权的身份验证应用程序和一个具有主要应用程序功能的 Erlang 应用程序。流程如下:

  • 客户端使用凭证向 Auth Application 发出 HTTP 请求;

  • Auth Application 检查 creds,生成 token 并通过 HTTP 请求发送到 Erlang Cluster;

  • Erlang 应用程序确认收到令牌并向 Auth 应用程序发送带有确认的 HTTP 响应;

  • Auth App 向客户端应用程序发送 HTTP 响应。此响应包括生成的令牌;

  • 客户端使用令牌通过我们的 HAProxy 负载均衡器与 Erlang 应用程序建立 websocket 连接。

这是我们的基本流程,稍作修改。我们在 Erlang 应用程序中添加了一个简单的模块,用于跟踪每个 Erlang 节点上的 websocket 连接数量。由于 Erlang 的 “分布式” 特性,每个节点都知道其他节点的连接。

所以我们可以选择一个连接较少的节点。我们获取此节点的公网 IP 地址,然后发送回 auth 应用程序。然后,身份验证应用程序将此 IP 与令牌一起发送回客户端。客户端使用收到的 IP 地址和令牌建立 WS 连接。所以最终的图表是这样的:

现在我们可以:

  • 摆脱 WS 负载均衡器,这使我们的系统不那么复杂;

  • 添加 Erlang 节点,而无需重新配置系统的其他部分。

另外:

  • WS 连接现在在 Erlang 节点之间均匀分布;

  • 该系统可轻松水平扩展;

  • 我们不必对 Erlang 节点使用弹性 IP。

综上所述,WebSocket负载均衡是一项复杂但重要的技术,它能够提高系统的可用性、可扩展性和性能。在设计和实现WebSocket负载均衡方案时,需要充分考虑WebSocket的特殊需求,并选择合适的负载均衡器和策略进行配置和优化。

负载均衡 大并发 WebSocket 物联网