Nikita Shirokov和RanjeethDasineni
全球数十亿人在使用Facebook服务,为此我们的基础设施工程师开发了一系列系统来优化流量,并为每个人确保快速可靠的访问。今天我们在开源道路上又迈出了一步:发布了Katran转发平面软件库,该软件库在底层支持Facebook基础设施中所用的网络负载均衡系统。Katran提供了基于软件的负载均衡解决方案,完全重新设计的转发平台充分利用了内核工程方面最近的两个创新:eXpress数据路径(XDP)和eBPF虚拟机。如今Katran部署在Facebook入网点(PoP)的大批后端服务器上,它帮助我们提高了网络负载均衡的性能和可扩展性,并减少了低效问题(比如没有入站数据包时的繁忙循环)。我们希望通过与开源社区共享Katran,其他人也能够提其负载均衡系统的性能,将Katran用作未来工作的基础。
艰巨挑战:在Facebook的庞大环境下处理请求
为了在Facebook的庞大环境下管理流量,我们部署了一个全球分布式入网点网络,充当数据中心的代理系统。鉴于请求数量极大,入网点和数据中心都面临这个艰巨挑战:让大批(后端)服务器在外界看来如同单一虚拟单元,又可以在那些后端服务器之间高效地分配工作负载。
这类挑战通常通过在每个位置向互联网通告虚拟IP地址(VIP)来加以解决。发往VIP的数据包随后在后端服务器之间无缝地分配。然而,分配算法需要考虑到这一点:后端服务器通常在应用层运行,并终止TCP连接。这项重任由网络负载均衡系统(常常名为第4层负载均衡系统或L4LB,因为它对数据包进行操作,而不是处理应用层请求)来处理。图1表明了L4LB相对于其他网络部件的作用。
图1:网络负载均衡系统面对几台运行后端应用程序的后端服务器,将来自每个客户端连接的所有数据包稳定地发送到一台独特的后端服务器。
对高性能负载均衡系统提出的要求
L4LB的性能对管理延迟和扩展后端服务器的数量来说特别重要,因为L4LB在需要处理每个入站数据包的路径上。性能通常按L4LB能够处理的每秒峰值数据包(pps)来衡量。传统上,工程师们青睐使用基于硬件的解决方案来完成这项任务,因为它们通常使用加速器来减轻主CPU的负担,比如专用集成电路(ASIC)或现场可编程门阵列(FPGA)。然而,硬件方案的缺点之一是,它限制了系统的灵活性。为了有效地满足Facebook的需求,网络负载均衡系统须满足下列要求:
•在大众化Linux服务器上运行。这让我们得以在部分或所有目前部署的大批服务器上运行负载均衡系统。基于软件的负载均衡系统满足这个标准。
•与特定服务器上的其他服务共存。这就不需要专门运行负载均衡系统的专用服务器,因而提高了容错性。
允许低干扰维护。Facebook的软件必须能够迅速演进,以支持新的或改进的产品和服务。对于负载均衡系统和后端层来说,维护和升级是常规,而不是例外。执行这些任务过程 中尽量减少干扰让我们得以更快地迭代。
易于检测和调试。所有大型分布式基础设施都必须应对异常和意外事件,因此缩短调试和排查问题的时间很重要。负载均衡系统需要易于检测,并与tcpdump之类的标准工具兼容。
为了满足这些要求,我们设计了一种高性能的软件网络负载均衡系统。我们的第一代L4LB基于IPVS内核模块,满足了Facebook四年多的需求。然而,它未能达到与其他服务(尤其是后端)共存的目标。在第二次迭代中,我们利用了eXpress数据路径(XDP)框架和新的BPF虚拟机(eBPF),让软件负载均衡系统与后端在大量机器上一起运行。图2显示了两代L4LB之间的关键区别。
图2:两代L4LB之间的区别。请注意,两者都是在后端服务器上运行的软件负载均衡系统。Katran(右)让我们得以将负载均衡系统与后端应用程序放在一起运行,因而增强了负载均衡系统的能力。
第一代L4LB:基于OSS软件
使用第一代L4LB时,我们高度依赖现有的开源组件来实现大部分功能。这种方法帮助我们在短短几个月内更换了庞大部署环境中基于硬件的解决方案。这种设计有四大组件:
•VIP通告:该组件与L4LB前面的网络元件(通常是交换机)对等互联,只是向外界通告L4LB负责的虚拟IP地址。然后,交换机使用等价多路径(ECMP)机制,在通告VIP的L4LB之间分配数据包。由于轻巧灵活的设计,我们将ExaBGP用于VIP通告。
•后端服务器选择:为了将来自客户端的所有数据包发送到同一个后端,L4LB使用一致性哈希,该哈希取决于入站数据包的5元组(源地址、源端口、目的地地址、目的地端口和协议)。使用一致性哈希可确保属于传输连接的所有数据包都被发送到同一个后端,不管接收数据包的L4LB是哪个。这就不需要跨多个L4LB的任何状态同步。一致性哈希还保证后端离开或加入后端池时对现有连接的干扰最小。
•转发平面:一旦L4LB选择了适当的后端,数据包需要被转发到该主机。为了避免限制(比如L4LB和后端主机要在同一个L2域),我们使用了简单的IP-in-IP封装。这让我们得以将L4LB和后端主机放置在不同的机架中。我们使用IPVS内核模块进行封装。后端经过了配置,确保回送接口上有相应的VIP。这让后端得以将返回路径上的数据包直接发送到客户端(而不是L4LB)。这种优化常常名为直接服务器返回(DSR),让L4LB只受入站数据包数量的限制。
•控制平面:该组件执行各项功能,包括对后端服务器执行健康检查,提供简单的接口(通过配置文件)以添加或删除VIP,并提供简单的API以检查L4LB和后端服务器的状态。我们内部开发了这个组件。
每个L4LB还将每个5元组的后端选择作为查找表存储起来,避免重复计算未来数据包的哈希。这种状态是纯粹的优化,未必是为了检查正确性。这种设计符合上面列出的Facebook工作负载的几个要求,但存在一大缺点:将L4LB和后端都放在一个主机上增加了设备故障的可能性。即使在本地状态下,L4LB也是CPU密集型组件。为了隔离故障域,我们在一组不相关的机器上运行L4LB和后端服务器。在这种方案中,L4LB的数量少于后端服务器,这使得L4LB更容易受到负载突增的影响。数据包在由L4LB处理之前要经过常规的Linux网络堆栈,更是加剧了这个问题。
图3:第一代L4LB的概况。请注意,负载均衡系统和后端应用程序在不同机器上运行。不同的负载均衡系统做出一致的决策,无需任何状态同步。使用数据包封装让运行负载均衡系统的服务器和运行后端应用程序的服务器得以放置在不同机架中。在典型的部署环境下,L4LB数量与后端应用服务器数量之比非常小。
Katran:重新设计转发平面
Katran是我们的第二代L4LB,采用了完全重新设计的转发平面,比前一个版本有了显著改进。内核界最近的两个创新助力这种新设计:
XDP提供了一种快速的可编程网络数据路径,无需采用全面的内核旁路方法,可与Linux网络堆栈结合使用。(此处https://www.iovisor.org/technology/xdp有XDP方面的详细介绍。)
eBPF虚拟机在内核的特定区域运行用户空间提供的程序,因而提供了一种灵活、高效、更可靠的方法与Linux内核进行交互,并扩展功能。eBPF已在几个方面带来了显著的改进,包括追踪和过滤。(此处https://www.iovisor.org/technology/ebpf有更多的详细信息。)
该系统的总体架构与第一代L4LB相似:首先,ExaBGP向外界通告某一个Katran实例负责哪个VIPS。其次,发往VIP的数据包使用ECMP机制发送到Katran实例。最后,Katran选择一个后端,将数据包转发到正确的后端服务器。主要区别在于最后一步。
及早高效的数据包处理:Katran结合使用XDP与BPF程序来转发数据包。XDP在驱动程序模式下被启用后,数据包处理例程(BPF程序)在网卡(NIC)收到数据包之后、内核截获之前立即运行。面对每个入站数据包,XDP一律调用BPF程序。如果网卡有多个队列,为每一个队列并行调用该程序。用于处理数据包的BPF程序是无锁的,使用每个CPU特有的BPF映射。由于这种并行机制,性能可以随网卡的RX队列的数量呈线性扩展。Katran还支持“通用XDP”操作模式(而不是驱动程序模式),但性能受到影响。
成本低廉但更稳定的哈希:Katran使用Maglev哈希的扩展版来选择后端服务器。扩展版哈希的几项功能是,遇到后端服务器故障后可迅速恢复,更均匀地分配负载以及能够为不同的后端服务器设置不等的权重。这最后一项是重要功能,让我们得以轻松处理入网点和数据中心的硬件更新:我们只要设置适当的权重就可以兼容新一代硬件。尽管计算这个哈希的代码更具表达力,但很小巧,足以完全装入到L1缓存中。
更有弹性的本地状态:Katran处理数据包和计算哈希方面很高效,因而与本地状态表有了有趣的交互。我们发现,对后端服务器选择组件而言,计算哈希从运算方面来看常常比查找5元组的本地状态表来得容易。在本地状态表查找一路遍历到共享的最后一级缓存这种情况下,这个现象来得更明显。为了自然地充分利用这种现象,我们将查找表实施成LRU驱逐缓存。LRU缓存大小在启动时可加以配置,充当可调参数,在计算和查找之间求得平衡。我们凭经验选择了这些值,针对pps进行优化。此外,Katran提供了一个运行时“仅计算”开关,那样万一主机遇到灾难性的内存压力,就完全忽略LRU缓存。
对RSS友好的封装:接收端扩展(RSS)是网卡中的一个重要优化,旨在通过将来自每路数据流的数据包转发到单独的CPU,从而在CPU之间均匀地分配负载。Katran设计的封装技术可与RSS结合使用。不是为每个IP-in-IP数据包使用同样的外部源,而是使用不同的外部源IP来封装不同数据流中的数据包(比如有不同的5元组),但同一数据流中的数据包始终被分配同样的外部源IP。
图4:Katran为高速处理数据包提供了一条快速路径,无需借助全面的内核旁路。请注意,数据包通过内核/用户空间边界只有一次。这让我们得以在不牺牲性能的情况下,将L4LB和后端应用程序放在一起。
这些功能显著增强了L4LB的性能、灵活性和可扩展性。如果没有入站数据包,Katran的设计还消除了几乎不耗用任何CPU的接收路径上的繁忙循环。相比全面的内核旁路解决方案(比如DPDK),使用XDP便于我们在同一个主机上让Katran与任何应用程序一起运行,性能不会出现任何下降。今天Katran在我们的入网点上与后端服务器一起运行,L4LB与后端之比得到了改进。这还增强了面对负载猛增、主机故障和维护的适应能力。重新设计的转发平面是这一转变的核心。我们认为,若使用我们的转发平面,其他系统也能从中得益,于是我们开源了代码,并附有如何用它来设计L4LB的几个例子。
另外要考虑的事项
Katran在实现性能提升的某些假设和约束条件下运行。实际上,我们发觉这些约束条件相当合理,没有阻止我们的部署。我们认为,使用我们库的大多数用户会发现它们易于满足。我们在下面逐一列出:
Katran只在直接服务返回(DSR)模式下工作。
Katran是决定发往VIP的数据包的最终目的地的组件,所以网络需要先将数据包路由发送到Katran。这要求网络拓扑结构基于L3,比如数据包由IP路由发送,而不是由MAC地址路由发送。
Katran无法转发分段的数据包,也无法自行对数据库分段。这可以通过增加网络内部的最大传输单元(MTU)或更改来自后端的通告TCPMSS来缓解。(即使你增加了MTU,还是建议采取后一个措施。)
Katran不支持带有IP选项集的数据包。最大数据包大小不得超过3.5 KB。
Katran当初在构建时假设它将用于“一体化负载均衡系统”这个场景,即单一接口将用于“从用户到L4LB(入口)”的流量和“从L4LB到L7LB(出口)”的流量。
尽管存在上述这些限制,我们还是认为Katran为希望利用XDP和eBPF这两项卓越创新来构建高效负载均衡系统的用户和组织提供了一种出色的转发平面。我们乐意回答潜在的采用者在使用我们GitHub代码仓库(https://github.com/facebookincubator/katran)的过程中提出的任何问题,也始终欢迎合并请求(pull request)!
领取专属 10元无门槛券
私享最新 技术干货