本文的上半卷已经对负载均衡技术的概念、功能和拓扑结构进行了详尽的介绍,接下来将主要介绍各种负载均衡技术的现状、演变和前景。
L4 负载均衡技术的现状
L4 负载均衡器还有用么?
本文已经讨论了 L7 负载均衡器是如何适合当代网络协议,下文会更深入地介绍 L7 负载均衡器的功能。这是否意味着不再需要 L4 负载均衡器了?不!尽管我认为 L7 负载均衡器最终会完全取代处理服务间通信的 L4 负载均衡器,但 L4 负载均衡器在边缘层仍然非常有用,因为大多数现代大型分布式架构都使用两层的 L4/L7 负载均衡架构来进行互联网流量管理。边缘部署时在 L7 负载均衡器之前放置 L4 负载均衡器的好处是:
- 由于 L7 负载均衡器执行的是更复杂的针对应用程序流量的分析、转换和路由等工作,因此它们比优化过的 L4 负载均衡器处理的原始流量负载相对少一些(以每秒数据包数和每秒字节数测量)。这通常使得 L4 负载均衡器更适合处理特定类型的 DoS 攻击(例如,SYN 洪水攻击、整包洪水攻击等)。
- L7 负载均衡器发展得更活跃,部署得更普遍,也比 L4 负载均衡器有更多的 bug。在 L7 负载均衡器前面使用 L4 负载均衡器,比使用现代 L4 负载均衡器的部署机制更容易进行健康状态检查和流量过滤,这种机制通常使用 BGP 和 ECMP(下文会对此介绍更多细节)。而且,因为 L7 负载均衡器由于功能的复杂性而可能会有更多的 bug,所以使用 L4 负载均衡器可以绕过故障和异常,从而使整个系统更稳定。
接下来的章节,我会介绍几种不同的中间 / 边缘代理 L4 负载均衡器的设计。这些设计通常不适用于客户端库和 sidecar 代理拓扑结构。
TCP/UDP 终端负载均衡器
第一种仍在使用的 L4 负载均衡器是图 8中所示的负载均衡器。这和上文介绍 L4 负载均衡时看到的负载均衡器相同。在这种负载均衡器中,使用了 2 个离散的 TCP 连接:一个用在客户端和负载均衡器之间,另一个用在负载均衡器和后端之间。
L4 终端负载均衡器还在被使用是因为两个原因:
- 相对来说,它们实现起来更简单。
- 与客户端更近的连接终端有天然的性能优势(延迟更低)。特别是,如果一个负载均衡器可以放得与使用松散网络(例如蜂窝网络拓扑)的客户端更近,可以在数据被发送到可靠光纤转发器然后路由到最终目的地之前更快地进行转发。换句话说,这种负载均衡器可以用在原始 TCP 连接终端的入网点(Point of Presence,POP)。
TCP/UDP 直连负载均衡器
第二种 L4 负载均衡器是图 9中所示的直连负载均衡器。在这种负载均衡器中,负载均衡器不会终止 TCP 连接。相反的,在进行连接监测和网络地址转换(Network Address Translation,NAT)之后,每个连接的数据包
被直接发送到一个选中的后端。首先,让我们定义连接监测和 NAT:
- 连接监测:是保持跟踪所有活跃的 TCP 连接状态的过程。这些状态包括握手是否完成、是否收到 FIN、连接空闲时间、连接选中的后端等信息。
- NAT: NAT 是在通过负载均衡器时,使用连接监测获取的数据来改变 IP 或端口信息的过程。
同时使用连接监测和 NAT,负载均衡器可以让大多数原始 TCP 流量直接从客户端到达后端。例如,客户端向1.2.3.4:80
发起通信,选中的后端位于10.0.0.2:9000
。客户端 TCP 数据包会首先到达负载均衡器所在的1.2.3.4:80
。然后,负载均衡器会将目标地址的 IP 和端口改为10.0.0.2:9000
。它还会将源地址的 IP 和端口改为负载均衡器的 IP 地址。因此,当在 TCP 连接中响应时,数据包会返回到负载均衡器,然后在这里反向进行连接监测和网络地址转换。
为什么这种负载均衡器会取代上一章节介绍的终端负载均衡器,是因为它更复杂吗?其实,原因是:
- 性能和资源利用率: 因为直连负载均衡器不会终止 TCP 连接,所以它们不需要缓冲任何 TCP 连接窗口。每个连接存储的状态数量很少,而且通常从高效的 hash table 中查找。因此,直连负载均衡器本质上可以比终端负载均衡器处理更多数量的活跃连接和每秒数据包数(packets per second,PPS)。
- 允许后端执行自定义阻塞控制: TCP 阻塞控制是一种互联网上的端点用来控制数据发送量以避免可用带宽和缓冲区超出负载承受能力的机制。由于直连负载均衡器不会终止 TCP 连接,所以它不会参与阻塞控制。这就允许后端根据它们的应用程序实际情况来使用不同的阻塞控制算法。这也使得更容易对阻塞控制变更进行实验(例如,最近的 BBR 首秀)。
- 形成服务器直接返回和集群化的 L4 负载均衡的基线: 更高级的 L4 负载均衡技术,例如 DSR 和使用分布式一致性哈希搭建集群(接下来的章节会讨论),都需要使用直连负载均衡器。
服务器直接返回
图 10所示的是一个服务器直接返回(Direct server return,DSR)负载均衡器。DSR 是在前面介绍的直连负载均衡器的基础上进行了优化,只有流入的或请求的数据包会通过负载均衡器,流出的或响应的数据包绕过负载均衡器直接返回到客户端。使用 DSR 的主要原因是,在许多工作负载中,响应流量比请求流量多得多(例如,经典的 HTTP 请求 / 响应模式)。假设 10% 的流量是请求流量,90% 的流量是响应流量,使用一个只拥有原来直连负载均衡器 1/10 性能的 DSR 负载均衡器就可以满足系统的需求。由于一直以来负载均衡器都很贵,这种优化可以很大程度上减少系统成本并增加可靠性(能少花钱总是好的)。DSR 负载均衡器扩展了直连负载均衡器的以下几个概念:
- DSR 负载均衡器通常执行部分连接监测。由于响应数据包不经过负载均衡器,负载均衡器就不清楚完整 TCP 连接的状态。然而,负载均衡器可以通过查看客户端数据包和利用各种空闲超时来准确推断出连接状态。
- DSR 通常使用通用路由封装(Generic Routing Encapsulation,GRE)来将从负载均衡器发送给后端的 IP 数据包进行封装,而不是使用网络地址转换。因此,当后端收到封装过的数据包后将它解封,然后就知道客户端的原始 IP 地址和 TCP 端口。这就使得后端可以直接向客户端响应了,而不需要经过负载均衡器。
- DSR 负载均衡器非常重要的一个概念是,后端参与负载均衡。后端需要恰当地配置一个 GRE 隧道,并且根据网络安装的底层细节,后端可能会需要它自己进行连接监测、网络地址转换等。
注意,在直连负载均衡器和 DSR 负载均衡器的设计中,有很多种方法可以设置在负载均衡器和后端之间,例如连接监测、NAT 和 GRE 等。但是,这个话题超出了本文的讨论范围。
通过高可用对实现容错
直到现在,我们还在孤立地看待 L4 负载均衡器的设计。直连负载均衡器和 DSR 负载均衡器都需要一些连接监测和负载均衡器自身的状态。如果负载均衡器挂掉了会发生什么?如果负载均衡器的一个实例挂了,经过负载均衡器的所有连接都会中断。就应用程序来说,这也许会对应用程序的性能造成重大影响。
历史上,L4 负载均衡器主要从传统供应商(Cisco、Juniper、F5 等)采购。这些硬件设备非常昂贵,负责处理大量流量。为了避免单点故障中断所有连接以及造成严重的应用停用,负载均衡器通常以图 11所示的高可用对的形式部署。经典的高可用对负载均衡器安装有以下设计:
- 用高可用对边缘路由器提供虚拟 IP(virtual IP,VIP)。这些边缘路由器用边界网关协议(Border Gateway Protocol,BGP)来实现虚拟 IP。其中,主边缘路由器比备份路由器有更高的 BGP 权重,因此它在稳定状态下处理所有的流量。(BGP 是一个非常复杂的协议;本文中,仅仅将 BGP 看作是一种机制,网络设备通过这种机制可以从其它网络设备获取流量,而且每一条链路都有一个优先权重)。
- 类似地,主 L4 负载均衡器向边缘路由器宣称自己比备份负载均衡器有更高的 BGP 权重,因而它在稳定状态下处理所有流量。
- 主负载均衡器与备份负载均衡器是交叉连接的,共享所有的连接监测状态。因此,如果主负载均衡器挂了,备份负载均衡器可以接管处理所有活跃的连接。
- 这两个边缘路由器和两个负载均衡器都是交叉连接的。这意味着,如果其中一个边缘路由器或负载均衡器挂了,或者因为某些其它原因被降低了 BGP 权重,备份可以接管处理所有的流量。
许多高流量的互联网应用如今也是按照上面的设置运行的。然而,上面的方案有一些本质上的缺点:
- 考虑到性能利用率,虚拟 IP 必须在高可用负载均衡器对间正确地共享。如果单个虚拟 IP 发展到超出单个高可用对的处理能力,这个虚拟 IP 需要被分割成多个虚拟 IP。
- 系统的资源利用率很低。在稳定状态下,50% 的能力一直闲置。考虑到过去负载均衡器硬件非常昂贵,这导致大量的资金闲置。
- 现代的分布式系统设计比主动 / 备份设计提供更好的容错能力。例如,理想情况下,一个系统应该能够承受多个同时发生的故障并保持运行。如果主动和备份负载均衡器同时挂掉,高可用负载均衡器对容易受到故障影响。
- 供应商专卖的大型硬件设备非常昂贵并且出现供应商锁定的结果。通常用一些软件方案取代这些硬件设备更可取,这些软件方案可以水平扩展并且使用商用计算机服务器实现。
通过使用分布式一致性哈希集群实现容错和扩展
图 12: 通过负载均衡器集群和一致性哈希实现 L4 容错和扩展
上一章节介绍的通过高可用对实现 L4 负载均衡器的容错性,以及那些在设计中固有的问题。从 21 世纪初期到中期,大型互联网基础设施开始设计和部署图 12所示的新型的大型并行 L4 负载均衡系统。这些系统的目标是:
- 缓解上一章节介绍的高可用对设计的所有缺点。
- 从供应商专卖的硬件负载均衡器转向使用标准计算机服务器和 NIC 的商用软件解决方案。
这种 L4 负载均衡器设计在容错性和扩展性方面是最好的。它通过集群和分布式一致性哈希来实现这一点,其运行机制如下:
- N 个边缘路由器以等量的 BGP 权重声明所有任播虚拟 IP。用等价多路径路由(Equal-cost multi-path routing,ECMP)来确保,在大体上,来自单个 flow 的所有数据包到达相同的边缘路由器。flow 通常是包含源 IP/ 端口和目的 IP/ 端口的 4 元组。(总之,ECMP 是一种在一组使用一致性哈希的等量权重的网络链路上分发数据包的方法)。尽管边缘路由器自身不特别关心哪个数据包到哪里,但是通常来自同一个 flow 的所有数据包通过相同的链路集,通过这样来避免数据包乱序造成的性能下降。
- N 个 L4 负载均衡器以等量 BGP 权重向边缘路由器声明所有虚拟 IP。还是使用 ECMP,边缘路由器通常会为 flow 选择同一个负载均衡器。
- 每一个 L4 负载均衡器通常会执行部分连接监测,然后使用一致性哈希来为 flow 选择后端。使用 GRE 来封装从负载均衡器发送到后端的数据包。
- 然后使用 DSR 来通过边缘路由器直接从后端向客户端发送数据包。
- L4 负载均衡器实际使用的一致性哈希算法是一个热门研究领域。这些算法在平衡负载、最小化延迟、最小化后端变更时造成中断的时间以及最小化内存开销等方面进行了一些权衡。关于这个话题的完整讨论不在本文的讨论范围之内。
让我们看看上面的设计如何缓解高可用对方案的所有缺点:
- 可以按需增加新的边缘路由器和负载均衡器。在每一层使用一致性哈希来尽可能减少新增设备时受影响的 flow 的数量。
- 在保证足够的流量爆发边界和容错性的同时尽可能地提高系统的资源利用率。
- 边缘路由器和负载均衡器都可以使用商用硬件来构建,这只相当于使用传统硬件负载均衡器的成本的很少一部分。(更多内容详见下文)。
关于这种设计通常被问到的一个问题是“为什么边缘路由器不直接通过 ECMP 和后端通信?为什么我们还需要负载均衡器?”这么做的原因主要是为了缓解 DoS 攻击和减轻后端运维工作。没有负载均衡器,每个后端都不得不参与 BGP,在执行滚动部署时要困难得多。
所有现代 L4 负载均衡系统都采用这种设计(或者这种设计的变种)。最突出的众所周知的两个例子是 Google 的 Maglev 和 Amazon 的 NLB(Network Load Balancer)。目前还没有任何 OSS 负载均衡器实现这种设计,然而,有一家我了解的公司打算在 2018 年发布一款使用这种设计的面向 OSS 的负载均衡器。我对于这次发布非常兴奋,因为现代 L4 负载均衡器是 OSS 在网络领域非常重要的一块缺失。
L7 负载均衡技术的现状
在过去几年,L7 负载均衡器(代理)发展得如火如荼。这和在分布式系统中持续推动微服务架构的趋势是一致的。从根本上讲,固有故障的网络使用得越频繁越难以进行高效维护。此外,自动扩展、容器调度等技术的兴起,意味着在静态文件中提供静态 IP 的时代一去不复返了。现代系统不仅更多地使用网络,还变得更加动态化,这都需要在负载均衡器中提供新的功能。在本章节,我将简要总结现代 L7 负载均衡器中发展最快的一些领域。
协议支持
现代 L7 负载均衡器为多种协议增加明确支持。负载均衡器对应用程序流量了解得越多,它就能做更复杂的观测报告、高级负载均衡和路由等事情。例如,本文撰写时,Envoy 明确支持对 HTTP/1、HTTP/2、gRPC、Redis、MongoDB 和 DynamoDB 的 L7 协议解析和路由。在将来会加入可能会加入更多的协议,包括 MySQL 和 Kafka。
动态配置
正如上文描述的那样,分布式系统日益增强的动态化特性需要并行投入创建动态化和响应式控制系统。 Istio 就是这种系统的一个例子。请查看我博客上关于《service mesh data plane vs. control plane》的帖子,来了解更多关于这个话题的信息。
高级负载均衡
L7 负载均衡器现在通常内置支持高级的负载均衡功能,例如超时、重试、速率限制、断路、投影、缓冲、基于内容的路由等。
观测性
正如上文关于通用负载均衡器功能的描述,日益动态化的系统变得更加难以调试。稳健的协议规格观测报告可能是现代 L7 负载均衡器提供的最重要的功能。实际上,现在任何 L7 负载均衡方案都需要生成数据统计、分布式跟踪和自定义日志信息。
扩展性
现代 L7 负载均衡器的用户通常希望非常容易地扩展它们来增加自定义的功能。这可以通过编写可插拔的过滤器来实现,这些过滤器将加载到负载均衡器中。许多负载均衡器还支持编制脚本(通常是用 Lua)来新增自定义功能。
容错性
我在前面已经提到了不少关于 L4 负载均衡器容错性的内容。L7 负载均衡器的容错性怎么样?大体上,我们认为 L7 负载均衡器应该是可扩展和无状态的。使用商业化软件允许 L7 负载均衡器更容易进行水平扩展。此外,L7 负载均衡器的执行流程和状态监测比 L4 负载均衡器复杂得多。尝试去构建一个 L7 负载均衡器的高可用对在技术上是可行的,但是任务会比较艰巨。
总之,在 L4 和 L7 负载均衡领域,行业已经从高可用对方案转向通过一致性哈希来聚集的水平扩展系统方案。
此外
L7 负载均衡器正以惊人的速度演变。如果想查看 Envoy 提供的功能,请看 Envoy 的架构概述。
全局负载均衡和中心化的控制层
未来,负载均衡会更多地将单个的负载均衡器作为商业化设备。在我看来,真正的创新和商业机会都在控制层领域。图 13展示了一个全局负载均衡系统的例子。在这个例子中,发生了一些改变:
- 每一个 sidecar 代理都和三个不同区域的后端(A、B、C)通信。
- 如图所示,90% 的流量送往区域 C,而 5% 的流量分别送往区域 A 和区域 B。
- sidecar 代理和后端都定期向全局负载均衡器报告状态。这允许全局负载均衡器根据延迟、成本、负载、当前故障等信息来进行决策。
- 全局负载均衡器定期为每个 sidecar 代理配置当前路由信息。
全局负载均衡器越来越能够完成一个复杂的单个负载均衡器自身不能完成的事情。例如:
- 自动探测并绕过局部故障。
- 应用全局的安全和路由策略。
- 探测并缓解流量异常,包括使用机器学习和神经网络的 DDoS 攻击。
- 提供集中化的 UI 和视图,允许工程师在整体上了解和维护整个分布式系统。
为了实现全局负载均衡,作为数据层的负载均衡器必须有精确的动态配置能力。请查看我博客上关于 Envoy 的统一数据层 API 以及《service mesh data plane vs. control plane》的帖子,来获取更过关于这个主题的信息。
从硬件到软件的演变
到目前为止,本文只是简要地提到了硬件 vs 软件,主要是在提到过去的 L4 负载均衡器高可用对的时候。在这个领域的行业趋势是怎样的呢?
上面的推文是一种幽默的夸张,但也很好地总结了行业趋势:
- 一直以来,路由器和负载均衡器都是非常昂贵的供应商专卖硬件。
- 逐渐地,大部分供应商专卖的 L3/L4 网络设备被商业化服务器硬件、商业化 NIC 和基于像 IPVS 、 DPDK 以及 fd.io 这样的框架的专业软件方案取代。一台现代数据中心的花费不到 5 千美元的机器,使用 Linux 和以 DPDK 编写的自定义的用户空间应用程序,可以用非常小的数据包轻易饱和 80Gbps 的 NIC。同时,能够以惊人的总带宽和数据频率完成 ECMP 路由的又便宜又基础的路由器 / 交换机 ASIC 被打包成商业化路由器。
- 复杂的 L7 软件负载均衡器,例如 NGINX、HAProxy 和 Envoy,也在快速迭代和蚕食之前提到的负载均衡器供应商,例如 F5。因此,L7 负载均衡器也在逐步迈入商业化软件解决方案。
- 同时,行业整体也在朝着 IaaS、CaaS 和 FaaS 发展。由主流云服务商提供基础设施,意味着越来越少的工程师需要了解物理网络是如何工作的(这些是上文提到的“黑魔法”和“我们不再需要了解的东西”)。
负载均衡的现状总结和前景
本文要点如下:
- 负载均衡器是现代分布式系统中非常关键的组件。
- 负载均衡器通常分为两类:L4 和 L7。
- L4 和 L7 负载均衡器在现代架构中都会涉及到。
- L4 负载均衡器朝着水平扩展的分布式一致性哈希解决方案发展。
- 由于动态微服务架构的兴起,最近 L7 负载均衡器被大量使用。
- 全局负载均衡以及控制层和数据层的分离是负载均衡器的未来趋势,也是未来主要的创新点和商业机会。
- 行业正朝着网络解决方案的商业化 OSS 硬件和软件方向发展。我坚信,传统的负载均衡供应商(例如 F5)将会首先被 OSS 软件和云供应商取代。我认为,传统的路由器 / 交换机供应商,例如 Arista/Cumulus 等,在特定部署情况下还有一席之地,但是最终也会被公共云供应商和他们的本土物理网络所取代。
总之,在计算机网络领域,这是一个令人着迷的时期!面向大部分系统的 OSS 和软件正以惊人的速度迭代发展。此外,随着分布式系统继续通过“无服务器”化而变得动态化,基础网络和负载均衡系统将变得更加复杂。
查看英文原文: Introduction to modern network load balancing and proxying
感谢冬雨对本文的审校。
评论 1 条评论