现代网络负载均衡与代理(下)

817 阅读21分钟
原文链接: www.infoq.com

本文的上半卷已经对负载均衡技术的概念、功能和拓扑结构进行了详尽的介绍,接下来将主要介绍各种负载均衡技术的现状、演变和前景。

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终端负载均衡器


图8:终端负载均衡器

第一种仍在使用的L4负载均衡器是图8中所示的负载均衡器。这和上文介绍L4负载均衡时看到的负载均衡器相同。在这种负载均衡器中,使用了2个离散的TCP连接:一个用在客户端和负载均衡器之间,另一个用在负载均衡器和后端之间。

L4终端负载均衡器还在被使用是因为两个原因:

  1. 相对来说,它们实现起来更简单。
  2. 与客户端更近的连接终端有天然的性能优势(延迟更低)。特别是,如果一个负载均衡器可以放得与使用松散网络(例如蜂窝网络拓扑)的客户端更近,可以在数据被发送到可靠光纤转发器然后路由到最终目的地之前更快地进行转发。换句话说,这种负载均衡器可以用在原始TCP连接终端的入网点(Point of Presence,POP)。

TCP/UDP直连负载均衡器


图9:L4直连负载均衡器

第二种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:L4服务器直接返回

图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等。但是,这个话题超出了本文的讨论范围。

通过高可用对实现容错


图11:通过高可用对和连接监测实现L4容错

直到现在,我们还在孤立地看待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:全局负载均衡

未来,负载均衡会更多地将单个的负载均衡器作为商业化设备。在我看来,真正的创新和商业机会都在控制层领域。图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和基于像IPVSDPDK以及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

感谢冬雨对本文的审校。