现代四层负载均衡和代理

Jun 10, 2023 08:45 · 4625 words · 10 minute read Network

原文:https://blog.envoyproxy.io/introduction-to-modern-network-load-balancing-and-proxying-a57f6ff80236


负载均衡器拓扑类型

上面已经从高等级上概述了负载均衡,四层和七层负载均衡器的区别以及功能,接下来将介绍部署负载均衡器在各种分布式系统中的拓扑结构。

中间代理

Figure 4

如图 4 所示,中间代理拓扑可能是大家最熟悉的。该类别包括来自 Cisco、Juniper、F5 的硬件设备;像亚马逊的 ALB 和 NLB 以及 Google 的 Cloud Load Balancer 等云软件解决方案;以及 HAProxyNGINXEnvoy 这类纯软件自托管解决方案。中间代理的优点是简单。通常情况下,用户通过 DNS 连接负载均衡器,无须担心其他任何事情。缺点在于即使集群化,代理容易成为单点故障和扩展瓶颈。中间代理也通常是黑盒,使操作变得困难。这是客户端的问题?还是物理网络的问题?还是中间代理的问题?还是后端的问题?很难说。

边缘代理

Figure 5

图 5 中的边缘代理拓扑实际上只是中间代理的一种变体,负载均衡器通过互联网访问。在该场景下负载均衡器必须提供额外的 “API 网关”功能,例如 TLS 终结、限速、认证和复杂的流量路由。边缘代理的优缺点和中间代理相同。大型面向互联网的分布式系统中通常不可避免地部署了专用边缘代理。客户端通常使用服务所有者无法控制的网络库通过 DNS 访问系统。此外处于安全原因,最好有个单一网关将来自互联网的流量导入系统。

嵌入的客户端代理

Figure 6

为了避免中间代理拓扑结构固有的单点故障和扩展问题,更复杂的基础设施已经开始通过库将负载均衡器直接嵌入服务中,如图 6。库支持各种功能,但最著名和功能最丰富的例如 FinagleEureka/Ribbon/HystrixgRPC(基于谷歌叫做 Stubby 的内部系统)。这种解决方案的主要优点是它完全将负载均衡器的所有功能分布到每个客户端上,从而消除了单点故障和扩展问题。主要缺点是每种使用的语言都要实现一遍。分布式架构越来越“多语言”。在这种环境下,实现一个非常复杂的网络库的成本相当大。最后在大型服务架构上部署一次升级可能非常痛苦,生产环境中可能同时运行许多不同版本的库,增加操作的心智负担。

边车代理

Figure 7

如图 7 所示,边车代理是嵌入式客户端负载均衡器拓扑的变体。近年来,这种拓扑以“服务网格”被熟知。边车代理背后的想法是,在跳转到不同的进程带来轻微延迟的成本下,就能够获得嵌入式库方案的全部好处,无需被编程语言绑架。最受欢迎的边车代理负载均衡器包括 EnvoyNGINXHAProxyLinkerd。有关边车代理的细节,请查看介绍 Envoy 的博客服务网格数据面 vs. 控制面

总结不同负载均衡器拓扑的优缺点

  • 中间代理通常是最简单的负载均衡拓扑结构。但存在单点故障、扩展限制和操作黑盒问题。
  • 边缘代理与中间代理类似,但通常无法避免。
  • 嵌入式客户端库提供了最佳的性能和可扩展性,但要为每种语言都实现该库,并且需要跨所有服务升级该库。
  • 边车代理的性能不如嵌入式客户端库,但不会被限制所困扰。

总的来说,我认为边车代理(服务网格)将逐渐取代所有其他用于服务间通信的拓扑结构。在流量进入服务网格之前,边缘代理也是有必要的。

四层负载均衡的现状

四层负载均衡器仍然有用吗?

本文已经讨论了现代协议中七层负载均衡器的优越性,并会在下面更详细地介绍它的功能。这是否意味着四层负载均衡器不在有用?并非如此!尽管我认为对于服务间的通信来说七层负载均衡器最终将完全取代四层负载均衡器,但在边缘四层负载均衡器仍然非常重要因为所有现代大型分布式架构都使用两层 L4/L7 负载均衡器架构来处理互联网流量。边缘场景中在七层负载均衡器前放置专用的四层负载均衡器的优点:

  • 因为七层负载均衡器执行更复杂的应用程序流量分析、转换和路由,它们可以处理的原始流量负载不如优化的四层负载均衡器,所以四层负载均衡器是处理某些类型 DoS 攻击(例如 SYN 泛洪、通用数据包泛洪攻击)的更好位置。
  • 七层负载均衡器的开发往往比四层负载均衡器更活跃,部署得更多,而且 bug 也更多。在七层负载均衡器前面放一个可以执行健康检查的四层负载均衡器要比使用 BGP 和 ECMP 的现代四层负载均衡器容易得多。最后,因七层负载均衡器功能复杂,更容易出现 bug,因此四层负载均衡器会使得整个系统更稳定。

下面我将描述几种不同的中间/边缘代理四层负载均衡器的设计,不适用于客户端库和边车代理拓扑。

TCP/UDP 终结型负载均衡器

Figure 8

如图 8 所示,和中间代理一样,这类负载均衡器分别使用两条 TCP 连接:一个连接客户端,一个连接后端。

四层终结负载均衡器仍被广泛使用是因为:

  1. 它们相对容易实现
  2. 对有损网络重传更友好(蜂窝数据网络)

TCP/UDP 透传型负载均衡器

Figure 9

第二种四层负载均衡器如图 9 所示。这种负载均衡器,TCP 连接不会被负载均衡器终结,相反地在连接跟踪和 NAT(Network Address Translate)后,每个数据包被转发到所选的后端:

  • 连接跟踪(connection tracking):就是持续跟踪所有活动的 TCP 连接状态,包括诸如握手是否完成、是否收到 FIN、连接空闲时间有多长、选择那个后端处理该连接等信息。
  • NAT:NAT 是使用连接跟踪数据来改变经过负载均衡器的数据包的 IP 和端口等信息的过程。

同时使用连接跟踪和 NAT,负载均衡器可以从客户端透传大部分原始 TCP 流量到后端。例如,客户端正在与 1.2.3.4:80 通信,并且选中的后端是 10.0.0.2:9000。负载均衡器将数据包的目标 IP 和端口替换为 10.0.0.2:9000,还会将源 IP 替换成负载均衡器的 IP。因此当客户端应答 TCP 连接时,数据包将返回至负载均衡器,再次根据连接跟踪反向 NAT。

为什么要用这种负载均衡器来代替前面所说的终结型负载均衡器呢,它更复杂。有几点原因:

  • 性能和资源使用:因为透传型负载均衡器不终止 TCP 连接,它们无需缓冲任何 TCP 连接窗口。每个连接存储的状态量非常小,并且通过哈希表高效查找。因此,这种负载均衡器通常每秒能够处理更多的活动连接和数据包(PPS)。
  • 允许后端执行定制的拥塞控制TCP 拥塞控制通过调节数据发送速率来避免超过可用带宽和缓冲容量的机制。由于透传型负载均衡器不终结 TCP 连接,因此它不参与拥塞控制,后端可以根据应用程序的使用情况选择不同的拥塞控制算法(比如 BBR)。
  • 为直接服务器返回(DSR)和集群四层负载均衡提供基础:更先进的负载均衡技术,如 DSR 和分布式一致性哈希集群是需要透传型负载均衡器的。

直接服务器返回(DSR)

Figure 10

图 10 就是直接服务器返回(Direct Server Return)负载均衡器,基于上面的透传型。DSR 是一种优化,只有入向/请求数据包穿过负载均衡器;出向/应答数据包则绕过负载均衡器直接返回客户端。使用 DSR 的主要原因是许多工作负载,应答流量远大于请求流量(例如典型的 HTTP 请求/应答模式)。假设 10% 的是请求流量,90% 的是应答流量,使用 DSR 的话负载均衡器的容量只需要 1/10 就满足系统需求了。由于曾经负载均衡器非常贵,这种类型的优化对系统成本和可靠性(越少越好)产生重大的影响。DSR 负载均衡器通过以下方式扩展了透传型负载均衡器的概念:

  • 负载均衡器通常会执行部分连接跟踪,由于应答数据包不经过负载均衡器,它就无法了解完整的 TCP 连接状态。但是通过观察客户端数据包并使用多种空闲超时时间,负载均衡器可以推测出状态。
  • 负载均衡器通常使用 GRE(Generic Routing Encapsulation)来封装从它发向后端的 IP 数据包,而非 NAT。因此后端可以通过解封数据包知道客户端的源 IP 地址和 TCP 端口。这使得后端能够直接响应客户端,无需将应答数据包发回负载均衡器。
  • 后端也是 DSR 负载均衡器重要的部分,参与负载均衡。后端需要正确配置 GRE 隧道,并且根据网络的底层细节可能要自己来跟踪连接、NAT。

高可用实现容错

Figure 11

到此为止,我们一直在思考独立的四层负载均衡器的设计。无论透传型还是 DSR 都需要在负载均衡器本身中进行连接跟踪和状态管理。如果负载均衡器挂了怎么办?单个负载均衡器出现故障,所有经过它的连接都会被切断,可能会对应用程序产生重大影响。

以前的四层负载均衡器是从供应商(Cisco、Juniper、F5 等)购买的硬件设备,非常昂贵而且处理大量流量。为了避免单点故障导致所有连接中断造成应用程序瘫痪,通常会部署一对可用对负载均衡器,如图 11 所示。搭建典型的 HA 负载均衡器这样设计:

  • 一对 HA 边缘路由器服务于若干虚拟 IP(VIP)。这些边缘路由器使用 BGP 协议发布 VIP。主边缘路由器比备机的 BGP 权重更大,因此在稳定状态下它将处理所有流量。
  • 同样地,主四层负载均衡器通过比备机更高的 BGP 权重向边缘路由器公告自己,因此在稳定状态下它会服务于所有流量。
  • 主负载均衡器与备机交叉连接,并共享其所有连接跟踪状态。因此如果主机挂了,备机就可以接管所有活动连接。
  • 两个边缘路由器和两个负载均衡器都交叉连接,某一方挂了,或因其他原因撤销 BGP 公告,备机可以接管所有流量。

但是以上方式存在重大缺陷

  • 考虑到容器,VIP 必须被正确地分片到 HA 负载均衡器对中。如果单个 VIP 增长超过单个 HA对 的容量,则需要将该 VIP 拆分为多个。
  • 系统的资源使用率很低,在稳定状态下,50% 的容量处于空闲。硬件负载均衡器非常贵,这样很浪费。
  • 现代分布式系统设计更倾向于比主备模式更高的容错能力。在理想情况下,一个系统要能够承受多个组件同事故障并继续运行。主备负载均衡器是有可能全挂的。
  • 专用大型硬件设备非常贵,并导致供应商锁死。通常希望使用商业服务器构建可水平扩展的软件解决方案来替换硬件设备。

通过分布式一致性哈希集群实现容错和扩展

Figure 12

从 2000 年开始,大型互联网基础设施开始设计和部署高度并行化的四层负载均衡系统。这些系统的目标是:

  • 解决 HA 双机对架构的缺陷
  • 抛弃供应商的专用硬件设备,转向使用标准服务器和网卡构建的通用软件解决方案。

这种四层负载均衡器设计的工作原理如下:

  • N 台边缘路由器以相同权重的 BGP 公告所有 Anycast VIP。使用等价多路径路由(ECMP)确保通常情况下,单条流中所有数据包都到达同一个边缘路由器。流是包括源 IP/端口和目标 IP/端口的四元组。简而言之,ECMP 是一种使用一致性哈希将数据包分发到一组具有相同权重的网络连接的方法。虽然边缘路由器本身不关心哪些数据包到达哪里,但通常一个流的所有数据包最好穿越同一组链路,以避免数据包乱序导致性能降低。
  • N 台四层负载均衡器以相同的 BGP 权重向边缘路由器公告所有 VIP。再次使用 ECMP,边缘路由器通常会为流选择相同的负载均衡器。
  • 每台四层负载均衡器通常会执行部分连接跟踪,然后使用一致性哈希来选择流的后端。GRE 用于封装从负载均衡器发送到后端的数据包。
  • 使用 DSR 通过边缘路由器将数据包直接从后端发送到客户端。
  • 四层负载均衡器使用的一致性哈希算法也是一个活跃的研究领域。要在均衡负载、最小化延迟、最小化后端更改期间的中断和最小化内存开销之间权衡。

现在我们来看看上述设计如何缓解主备模式的缺陷:

  • 可以根据需求添加新的边缘路由器和负载均衡器。使用一致性哈希来尽可能减少添加新机器对流量的影响。
  • 系统资源使用率可以相当高,同时保持足够的爆发余量和容错能力。
  • 边缘路由器和负载均衡器都可以使用商业服务器搭建,成本比传统硬件负载均衡器小得多。

为什么边缘路由器不直接通过 ECMP 与后端通信?为什么要负载均衡器?主要原因是防止 DoS 攻击和简化后端。如果没有负载均衡器,每个后端都必须参与 BGP,在执行滚动部署时会很困难。

所有现代的四层负载均衡系统都在朝这个设计发展。目前最著名的两个公开的项目是 Google 的 Maglev 和 AWS 的 NLB