作者:Matt Klein
译者:穿过生命散发芬芳°F
原文链接:
https://blog.envoyproxy.io/introduction-to-modern-network-load-balancing-and- proxying-a57f6ff80236
最近我注意到,关于现代网络负载均衡与代理的入门介绍资料非常缺乏。怎么会这 样呢?负载均衡是构建可靠的分布式系统所需的核心概念之一。是否有高质量素材?我搜索 了一下,发现有用的东西确实很少。关于负载均衡和代理服务器的维基百科文章包含了一些 概念的概述,特别是当它涉及到现代微服务体系结构时,并没有进行深入的阐释。
在这篇文章中,我试图通过介绍现代网络负载均衡与代理来弥补现有信息的不足。坦率地说, 这是一个可以写一整本书的宏大主题。为了稍微保持这篇帖子的长度,我尝试将一组复杂的 主题提炼成一个简单的概述;根据兴趣和反馈,个别主题在以后将考虑更详细的后续帖子更 新。
先做了一点关于我为什么写这篇帖子的背景介绍,让我们开始!
1
什么是网络负载均衡与代理
维基百科将负载均衡定义如下: 在计算中,负载均衡改进了跨多个计算资源(如计算机、计算机集群、网络连接、中央处理单 元或磁盘驱动器)的工作负载分布。负载均衡的目的是优化资源的使用,最大限度地提高吞 吐量,最大限度地减少响应时间,并避免任何单一资源的过载。使用具有负载均衡的多个组 件而不是单个组件,可以通过冗余提高可靠性和可用性。负载均衡通常涉及专用软件或硬件, 如多层交换机或域名系统服务器。
上述定义适用于计算的所有方面,而不仅仅是网络。操作系统使用负载均衡来跨物理处理器 调度任务,容器编排(如 Kubernetes)使用负载均衡来跨计算集群调度任务,网络负载均衡器 使用负载均衡来跨可用后端调度网络任务。这篇文章的剩余部分将只讨论网络负载均衡。
图 1 网络负载均衡概况
图 1 显示了网络负载均衡的总体概况。多个客户端正在向多个后端请求资源。负载均衡器
位于客户端和后端之间,总体执行几个关键任务:
在分布式系统中正确使用负载均衡提供了几个好处:
负载均衡器VS代理
当谈到网络负载均衡器时,行业内的术语负载均衡器和代理服务器大致可以互换使用。这 篇文章也会把这两个术语视为同等。(目前,并不是所有代理都是负载均衡器,但是绝大多 数代理将负载均衡作为主要功能)。
还有人认为,当负载均衡作为嵌入式客户机库的一部分来完成时,负载均衡器并不是真正 的代理。然而,我认为这种区别给本已令人困惑的主题增加了不必要的麻烦。负载均衡器 拓扑类型将在下面进行详细讨论,本文将嵌入式负载均衡器拓扑视为代理的一种特殊情 况。应用程序通过嵌入式库进行代理,该库提供与应用程序过程外部的负载均衡器相同的 功能。
四层(连接/会话)负载均衡
在业界讨论负载均衡时,解决方案通常被归为两类:四层和七层。这些类别是指 OSI 模型的 第 4 层和第 7 层。正是这些原因,当我讨论七层负载均衡时,我认为我们使用这些术语是 不可取的。OSI 模型无法很好描述负载均衡解决方案的复杂性,负载均衡方案除了包括传 统的第 4 层协议,如 TCP 和 UDP,还包括其他不同 OSI 层上协议内容。例如,如果四层TCP 负载均衡器也支持 TLS 终结,它算七层负载均衡器吗?
图 2 TCP 四层终结负载均衡
图 2 显示了一个传统的四层 TCP 负载均衡器。在这种情况下,客户端建立一个到负载均衡 器的 TCP 连接。负载均衡器终结该连接(即直接响应 SYN),然后选择一个后端,并与该后端建立一个新的 TCP 连接(即发送一个新的 SYN)。图的细节并不重要,将在下面的四层负载均 衡小节中详细讨论。
本节的主要内容是四层负载均衡器通常只在四层 TCP/UDP 连接/会话级别上运行。因此, 负载均衡器通过转发数据,并确保来自同一会话的字节在同一后端结束。四层负载均衡器 不知道它正在转发数据的任何应用程序细节。数据内容可以是 HTTP, Redis, MongoDB,或任 何应用协议。
七层(应用)负载均衡
四层负载均衡很简单,并且仍然被广泛使用。四层负载均衡有哪些缺点是七层(应用)负载均衡来解决的呢?以下几个四层案例:
在上面场景中,选择处理客户端 B 的后端负载约是选择处理客户端 A 的 3000 倍!这是一个 大问题,违背负载均衡的初衷。还要注意,这个问题发生在任何多路复用、保活的协议 上。(多路复用意味着通过单个四层连接发送并发的应用程序请求,而保活意味着当没有活 动请求时也不关闭连接)。所有的现代协议都是为了提高效率都使用多路复用和保活机制。(创建连接通常是昂贵的,特别是当连接使用 TLS 加密时),所以四层负载均衡器问题随着时 间的推移变得越来越不均衡。这个问题由七层负载均衡器解决。
图 3 显示了一个七层 HTTP/2 负载均衡器。在本例中,客户端创建一个到负载均衡器的HTTP/2 TCP 连接。负载均衡器创建连接到两个后端。当客户端向负载均衡器发送两个HTTP/2 流时,流 1 被发送到后端 1,流 2 被发送到后端 2。因此,即使请求负载有很大差 异的客户端也会在后端之间实现高效地分发。这就是为什么七层负载均衡对现代协议如此 重要的原因。(由于能够识别应用程序流量,七层负载均衡产生了许多其他好处,这将在下 面进行更详细的介绍)。
七层负载均衡和 OSI 模型
正如我在上面关于四层负载均衡的部分中所说的,使用 OSI 模型来描述负载均衡特性是困 难的。原因是,像 OSI 模型所描述的那样,七层它本身包含了负载均衡抽象的多个子层。例如,对于 HTTP 流量有以下子层:
高级的七层负载均衡器可以提供与上述每个子层相关的功能。另外一些七层负载均衡器可能 只有一小部分功能,也将其置于七层类别中。简而言之,从功能比较的角度来看,七层负载 均衡器比四层类别要丰富得多。(当然,本节仅涉及 HTTP; Redis,Kafka,MongoDB 等七层 应用协议比较适用于于七层负载均衡)。
2
负载均衡器功能
在本节中,我将简要概述负载均衡器提供的高级功能。但并非所有负载均衡器都提供所有功 能。
服务发现
服务发现是负载均衡器确定可用后端集合的过程。方法多种多样,举例如下:
健康检查
健康检查是负载均衡器确定后端是否可用来提供服务的过程。健康检查通常分为两类:
负载均衡
是的,负载均衡器必须实现负载的均衡!在给定一组健康的后端中,如何选择哪些后端接受 连接或请求?负载均衡算法是一个活跃的研究领域,从简单的算法(如随机选择和轮询),到考 虑可变延迟和后端负载来判断更复杂的算法。考虑到性能和简易性,最流行的负载均衡算法 之一是最小连接数请求负载均衡算法。
会话保持
在某些应用程序中,对于同一会话的请求到达同一的后端非常重要。这对于缓存、临时复杂 构造状态是必须的。会话的定义各不相同,可能包括 HTTP cookie、客户端连接的属性或其 他一些属性。许多七层负载均衡器都支持会话保持。顺便说一句,我要指出会话保持本质上 是不可靠的(处理会话的后端可能会宕掉),因此在设计依赖于会话保持的系统时要更谨慎。
TLS 终结
TLS 的话题及其在边缘服务和保护服务间通信中的作用都值得一提。也就是说,许多七层负载均衡器会进行大量的 TLS 处理,包括终结、证书校验和绑定、使用 SNI 提供证书服务等等。
可观察性
正如我经常所说的:“可观察性,可观察性,可观察性。” 网络本质上是不可靠的,负载均衡 器通常负责导出统计信息,跟踪信息和日志,帮助管理员找出问题所在,以便他们解决问题。负载均衡器的可观察性输出差异很大。最先进的负载均衡器提供了丰富的输出,其中包括统 计数据,分布式跟踪和可自定义的日志记录。我认为,增强的可观察性不是与生俱来的。负 载均衡器必须做附加的工作才能满足它。但是,数据带来的好处远远超过了对性能影响。
安全性和 Dos 防范
特别是在边缘部署拓扑结构中(见下文),负载均衡器经常要实现各种安全特性,包括速率限制、身份验证和 DoS 防范(例如,IP 地址标签和标识、tarpitting 等)。
配置和控制平面
负载均衡器都需要配置。在大型部署中,这可能成为一项艰巨的任务。通常,配置负载均衡 器的系统称为“控制平面”,其实现方式差异很大。有关此主题的更多信息,请参见我关于服 务网格数据平面与控制平面的文章。
更多
本节仅介绍了负载均衡器提供的功能类型。其他讨论可以在下面的七层负载均衡器部分中找 到。
3
负载均衡器拓扑类型
我已经概述了什么是负载均衡器,四层和七层负载均衡器之间的区别以及负载均衡器功能, 接下来我将继续介绍部署负载均衡器的各种分布式系统拓扑。(以下每种拓扑都适用于四层 和七层负载均衡器部署)。
中间代理
图 4 中间代理负载均衡拓扑
图 4 所示的中间代理拓扑可能是大多数读者最熟悉的部署负载均衡器方法。此类别包含 Cisco,Juniper,F5 等的硬件设备;云软件解决方案,例如亚马逊的 ALB 和 NLB 以及 Google 的 Cloud
Load Balancer;以及纯软件自托管解决方案,例如 HAProxy,NGINX 和 Envoy。中间代理解决 方案的优点是对于用户来说比较简单。通常,用户通过 DNS 连接到负载均衡器,而无需担 心其他事情。中间代理解决方案的缺点是,代理(即使是群集的)也存在单点故障以及扩展 瓶颈。中间代理通常也是一个黑匣子,使运维变得困难。无法知道哪里出现了问题?在客户 端?在物理网络中?在中间代理?还是在后端?很难定位。
边缘代理
图 5:边缘代理负载均衡拓扑
边缘代理拓扑如图 5 所示实际上只是中间代理拓扑的一种变体,可以通过 Internet 访问负载 均衡器。在这种情况下,负载均衡器通常必须提供额外的“ API 网关”功能,例如 TLS 终结, 速率限制,身份验证和复杂的流量路由。边缘代理的优缺点与中间代理相同。需要注意的是, 通常在面向 Internet 的大型分布式系统中必须部署专用的边缘代理。客户端通常需要使用服 务所有者的任意网络库通过 DNS 访问系统(使用后面描述的嵌入式客户端库或 sidecar 代理 拓扑是不可行的,因为无法直接在客户端上运行)。另外,出于安全考虑,希望所有面向internet 流量由单一网关来接入系统。
嵌入式客户端库
图 6 通过嵌入式客户端库实现负载均衡
如图 6 所示,为了避免中间代理拓扑固有的单点故障和扩展问题,更成熟的基础架构已朝着 通过将负载均衡嵌入到客户端库的方式来实现。不同的库在支持的功能方面差异很大,但是 在此类别中有些知名且功能丰富的库包括 Finagle,Eureka/ Ribbon / Hystrix 和 gRPC(大致基 于在谷歌内部称为 Stubby 的系统)。
基于库的解决方案的主要优点是,它可以将负载均衡的 所有功能完全分发给每个客户端,从而消除了单点故障并解决了先前描述的扩展问题。基于 库的解决方案的主要缺点是组织使用的每种语言来都必须实现这种库。分布式架构变得越来 越“多语言”。在这种环境下,以各种不同语言重新实现极其复杂的网络库的成本可能变得高 昂。
最后,在大型服务架构上部署库升级可能非常痛苦,并且在生产中可能会同时并行着各 种不同的版本,这也增加了运维的负担。综上所述,在能够限制编程语言使用并克服库升级带来的麻烦的前提下,这种库可以来说是 成功的。
Sidecar 代理
图 7 通过 Sidecar 代理实现负载均衡
嵌入式客户端库负载均衡的一种变体就是如图 7 所示 sidecar 代理拓扑。近年来,这种拓扑 已被普及为“服务网格”。Sidecar 代理背后的思路是,以各进程间通信而导致的轻微延迟损失 为代价,无需任何编程语言锁定即可获得嵌入式库方法的各种优点。在撰写本文时,最受欢 迎的 Sidecar 代理负载均衡是 Envoy,NGINX,HAProxy 和 Linkerd。有关 Sidecar 代理方法的 更详细处理,请参阅我的博客文章,介绍 Envoy、服务网格数据平面与控制平面。
不同负载均衡器拓扑的总结和优缺点
总的来说,我认为 sidecar 代理拓扑(服务网格)将逐渐取代其他所有拓扑,以实现服务到服务 的通信。在流量进入服务网格之前,边缘代理拓扑则不可替代。
4
四层负载均衡的现状
四层负载均衡是否还在使用?
这篇文章已经讨论了七层负载均衡器在现代协议中的好处,并将在下文中进一步详细讨论七层负载均衡器的更多特性。这是否意味着四层负载均衡器不需要在使用了?不是的!尽管在我看来,七层负载均衡器最终将会在服务对服务通信中完全取代四层负载均衡器,但四层负载均衡器仍然是非常重要的,因为几乎所有现代大型分布式架构都使用两层的四层/七层负载均衡架构来处理互联网流量。在边缘部署中,将专用四层负载均衡器置于七层负载均衡器之前的好处是:
在下面的部分中,我将介绍几种不同的中间/边缘代理四层负载均衡器的设计。下面的设计 通常不适用于客户端库和 sidecar 代理拓扑。
TCP/UDP 终结负载均衡器
仍在使用的第一种四层负载均衡器是图 8 中所示的四层终结负载均衡器。这与我们在上面 的四层负载均衡介绍中看到的是相同。在这种类型的负载均衡器中,使用了两个独立的 TCP连接:一个在客户端与负载均衡器之间,一个在负载均衡器与后端之间。
仍然使用这种负载均衡器有两个原因:
1. 实现起来相对简单。 2. 接近客户端(低延迟)的连接终止会对性能产生重大影响。具体来说,如果这类负载均衡器 可以放置在靠近使用有损耗网络(如蜂窝网络)的客户端,那么数据在进入可靠的光纤并传输 到最终位置之前,更容易发生重传。换句话说,这种类型的负载均衡器适用于在 POP 场景 中对原始 TCP 连接的终止。
TCP/UDP 直通(透传)负载均衡器
图 9 四层直通负载均衡器
第二种四层负载均衡器是图 9 中所示的直通负载均衡器。在这种类型的负载均衡器中,TCP连接不会被负载均衡器终结。而是在进行连接跟踪和网络地址转换(NAT)之后,将每个连 接的数据包转发到选定的后端。首先,让我们来看下连接跟踪和 NAT 的定义:
通过使用连接跟踪和 NAT,负载均衡器可以将大部分原始 TCP 流量从客户端传递到后端。例 如,假设客户端正在与 1.2.3.4:80 通信,而所选后端是 10.0.0.2:9000。客户端 TCP 包将到达1.2.3.4:80 负载均衡器。然后负载均衡器将用 10.0.0.2:9000 来替换数据包的目标 IP 和端口。同时还将包的源 IP 替换为负载均衡器的 IP 地址。因此,当后端对 TCP 连接做出响应时,包 将返回到负载均衡器,再通过负载均衡器上的连接跟踪表和 NAT 表,将数据送回客户端。
既然这种类型的负载均衡器更复杂,为什么要用它来代替上一节中描述的四层终结负载均衡 器呢?有几个原因:
直接服务器返回(DSR)
图 10 四层直接服务器返回
直接服务器返回(DSR)负载均衡器如图 10 所示。DSR 构建在前一节中描述的直通负载均衡器 上。DSR 是一种优化方案,其中只有入站/请求包通过负载均衡器。出站/响应包绕过负载均 衡器直接返回到客户端。使用 DSR 的主要原因是,在许多工作负载中,响应流量比请求流量 要大很多(例如,典型的 HTTP 请求/响应模式)。假设 10%的流量是请求流量,那么 90%的流 量是响应流量,如果使用 DSR 负载均衡器,1/10 的容量就可以满足系统的需求。由于过去 的负载均衡器非常昂贵,这种类型的优化可能会对系统成本和可靠性产生重大影响。DSR 负 载均衡器扩展了直通负载均衡器的概念,如下所示:
请注意,在直通负载均衡器和 DSR 负载均衡器设计中,可以通过多种方式在负载均衡器和 后端之间建立连接跟踪,NAT,GRE 等。不过该主题超出了本文的范围,不再深入阐述。
通过高可用实现容错
图 11 通过 HA 和连接跟踪使用四层容错
到目前为止,我们一直在孤立地考虑四层负载均衡器的设计。不管直通负载均衡器还是 DSR负载均衡器本身都需要一些连接跟踪和状态。如果负载均衡器宕机了怎么办?那么所有经过 负载均衡器的连接将被中断。根据应用程序的不同,这可能会对应用程序不同的影响。
在过去,四层负载均衡器是从典型的供应商(Cisco、Juniper、F5 等)购买的硬件设备。这些设 备非常昂贵,可以处理大量的流量。为了避免单个负载均衡器故障切断所有连接并导致大量 应用程序中断,负载均衡器通常部署在高可用部署,如图 11 所示。一个典型的高可用负载 均衡器有如下设计:
上面的设置目前还有很多大流量的 Internet 应用程序在使用。然而,上述方法也有一些缺点:
通过具有分布式一致性哈希集群进行容错和扩展
上一节介绍了通过 HA 主备方式来实现四层负载均衡器容错,以及该设计中存在的问题。从2000 年代早期到中期,大型互联网基础设施开始设计和部署新的如图 12 所示的大规模并行 四层负载均衡系统。这些系统的目标是:
这种四层负载均衡器设计是通过集群和分布式一致性哈希实现容错和扩展。其工作原理如 下:
让我们看看上面的设计如何解决 HA 主备方式的缺点:
关于这种设计通常会被问到的一个问题是“为什么边缘路由器不通过 ECMP 直接与后端通 信?我们为什么还需要负载均衡器呢?”这样做的主要原因是 DoS 防范和后端操作简易性。如 果没有负载均衡器,每个后端都将不得不参与 BGP,并且在执行滚动部署时将会更加困难。
所有现代的四层负载均衡系统都在朝着这种设计(或它的某些变体)迈进。最著名的两个广为 人知的例子是谷歌的 Maglev 和亚马逊的网络负载均衡器(NLB)。目前还没有任何开源负载均 衡器实现这种设计,然而,据我所知,有一家公司计划在 2018 年发布一个开源软件。我对 这个版本感到非常兴奋,这将填补现代的四层负载均衡器在开源软件中的空白部分。
5
七层负载均衡的现状
是的确实。在过去的几年中,七层负载均衡器/代理的开发出现了复苏。这与分布式系统中 不断推进的微服务体系结构不谋而合。从根本上说,当网络被更频繁地使用时,其存在的网 络问题会使其更难以有效地运行。此外,自动扩展、容器编排等新技术的兴起,意味着在静 态文件中提供静态 ip 的日子已经一去不复返了。系统不仅更多地利用网络,而且变得更加 动态,也需要负载均衡器的新功能。在这一节中,我将简要总结现代七层负载均衡器中发展 较快的领域。
协议支持
现代的七层负载均衡器增加了对许多不同协议的显式支持。负载均衡器对应用程序识别得越 多,它就能在可观察性输出、高级负载均衡和路由等方面做得越好。例如,在撰写本文时,Envoy 明确支持七层协议解析和路由包括 HTTP/1, HTTP2, gRPC, Redis, MongoDB,和 DynamoDB。未来可能会添加更多协议,包括 MySQL 和 Kafka。
动态配置
如上所述,分布式系统要求有可动态配置的功能来控制系统。Istio 就是这种系统的一个例子。关于这个话题的更多信息,请参阅我的文章“服务网格数据平面与控制平面”。
高级负载均衡
七层负载均衡器现在通常内置了很多高级负载均衡功能,例如超时、重试、速率限制、断路、Shadow、缓冲、基于内容的路由等。
可观察性
正如前面关于一般负载均衡器功能中所描述的,越来越动态的系统正在被部署,随之越来越 难以调试。健壮的协议规范可观察性输出可能是现代七层负载均衡器提供的最重要的功能之 一。现在,任何七层负载均衡解决方案实际上都需要输出统计数据、分布式跟踪和可定制的 日志记录。
可扩展性
现代七层负载均衡器的用户通常希望轻松地进行自定义功能。这个可以通过编写加载到负载 均衡器中的可插拔过滤器来实现。很多负载均衡器都支持脚本,比如 Lua。
容错
我在上面写了很多关于四层负载均衡器容错的内容。那么七层负载均衡器的容错能力如何?通常,我们将七层负载均衡器视为可丢弃的和无状态的。使用商用软件可以轻松地对使七层 负载均衡器进行水平扩展。此外,七层负载均衡器执行的处理和状态跟踪要比四层复杂得多。尝试构建一个七层负载均衡器的 HA 方式在技术上是可行的,但这将是一项艰巨的任务。
总的来说,在四层和七层负载均衡领域,业界正在从 HA 主备方式转向通过一致性哈希融合 的水平可扩展系统。
更多
七层负载均衡器正在以惊人的速度发展。有关 Envoy 所提供内容的例子,请参阅 Envoy 的架 构概述。
6
全局负载均衡和集中控制平面
图 13 全局负载均衡
未来的负载均衡会越来越多地将独立的负载均衡器视为成型商品设备。在我看来,真正的创 新和商业机会都在控制层面。图 13 显示了一个全局负载均衡系统的示例。在这个例子中, 一些不同的事情正在发生:
全局负载均衡器能够完成单个负载均衡器无法独立完成的复杂工作。例如:
为了实现全局负载均衡,用作数据平面的负载均衡器必须具有强大的动态配置功能。请参阅 我关于 Envoy 通用数据平面 API 以及服务网格数据平面与控制平面的帖子,以获得有关此主 题的更多信息。
到目前为止,这篇文章仅在在四层负载均衡器 HA 高可用部分简单地提到了硬件与软件的对 比,那么这方面的行业趋势是什么?
上一条推特虽略带幽默夸张,但仍然很好地概括了当前的趋势,如下:
8
结论和负载均衡的未来
总结一下,这篇文章的关键要点是:
总的来说,我认为这是计算机网络的迷人时代! 随着越来越多的系统走向开源软件方向,极 大提升了迭代速度。此外,随着分布式系统向“serverless”计算继续进军,底层网络和负载 均衡系统的复杂性也会相应地增加。