前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >现代网络负载平衡和代理介绍

现代网络负载平衡和代理介绍

作者头像
Techeek
发布2018-07-09 15:57:11
1.5K0
发布2018-07-09 15:57:11
举报
文章被收录于专栏:云计算云计算

原文作者:mattklein123

原文地址:https://blog.envoyproxy.io/introduction-to-modern-network-load-balancing-and-proxying-a57f6ff80236?source=search_post

我最近注意到,介绍现代网络的负载均衡及代理方面的有教育意义的介绍资料存在着一定的欠缺。我就在想:怎么会这样呢?作为构建可靠的分布式系统所需的核心要素,负载均衡肯定有很多高质量的资料才对吧?我搜索了一下,却发现这样的资料真的很少见。维基百科上介绍负载均衡代理服务器的文章对一些概念的阐述,尤其是在涉及到现代微服务架构时,都并不能流畅地介绍这个主题。用谷歌搜索负载均衡更是只找到一些服务商的页面,而它们充斥着各种时髦词语,罕见具体细节。

在本文里面,我会尝试把现在的网络负载均衡以及代理服务器方面的技术慢慢地讲解一遍,以此来填补这方面的资料的欠缺。这确实是一个内容很宽泛的主题,甚至能写本书来说。为了精简这篇文章的篇幅,我会试着去将各种各样的复杂概念用一个简述来讲解。如果反馈的效果不错,我也会考虑一下在后续的文章里面继续详细地介绍这一主题。

那么这就是对我撰写这篇文章的背景的一个简述 - 下面开始正片吧!

网络负载均衡和代理服务器是什么?

维基百科对负载均衡的定义如下:

In computing, load balancing improves the distribution of workloads across multiple computing resources, such as computers, a computer cluster, network links, central processing units, or disk drives. Load balancing aims to optimize resource use, maximize throughput, minimize response time, and avoid overload of any single resource. Using multiple components with load balancing instead of a single component may increase reliability and availability through redundancy. Load balancing usually involves dedicated software or hardware, such as a multilayer switch or a Domain Name System server process. 在计算领域里,负载均衡改善了在多个计算资源(比如计算机、计算机集群、网络链路、CPU,还有磁盘驱动器)之间分配工作负载的方式。负载均衡的目标在于最优化资源利用,最大化吞吐量,最小化响应时间,并规避任一计算资源的过载。使用处于负载均衡下的多重组件能取得比使用单一组件更高的可靠性,且通过冗余还能取得更高的可用性。负载均衡通常会用一些专门的软件或硬件来实现,比如多层交换机,或者一个域名系统服务器的进程。

上述定义引入了计算领域的全部概念,而并没有局限于计算机网络。操作系统可以基于负载均衡来在若干物理的处理器之间调度作业,容器编排器(如 Kubernetes)会基于负载均衡在计算机集群里面调度作业,网络负载均衡器也会基于负载均衡来在若干可用的服务端之间调度作业。本文只讨论网络上的负载均衡。

图 1:网络负载均衡
图 1:网络负载均衡

图 1 便是对网络负载均衡的一个高度概括。有些客户端会向一些服务端请求资源,而处于它们之间的负载均衡器就会执行这些关键任务:

  • 服务发现:系统中有哪个服务端可用?可用服务端的地址是什么(即负载均衡器要如何与服务端交互)?
  • 健康检查:现在哪些服务端能正常接受请求?
  • 负载均衡:现在应该基于什么算法来在正常运行的服务端之间均匀分配请求?

若是分布式系统里面的负载均衡用得好,那就会带来这些好处:

  • 命名抽象:客户端不需要管每一个服务端的存在与否(即不用自己发现服务)。客户端可以基于一种预定义的机制来找到负载均衡器,让负载均衡器来代理进行命名解析。这种预定义的机制可以写入一个内置的类库,也可以放在一个熟知的 DNS / IP / 端口上。本文还会在后面介绍一些细节。
  • 差错容忍:负载均衡器可以通过健康检查、各种算法,以及路由技术,使得传入流量能绕开某个故障的或过载的服务端。这就意味着运维人员可以在空闲的时候再去修复故障的服务端,而不一定要马上对其实施紧急修复以确保可用。
  • 改善性能开销:组成分布式系统的网络很少会是同构的。整个系统很可能会跨越好几个网络区域,而在同区域的网络常常是相对欠利用(undersubscribed)的,但在跨区域的情况里,过利用(oversubscribed)又成了常态(这里的欠 / 过利用的指标是可通过网络适配器来使用的带宽值,以及不同路由器间的链路的空闲带宽值)。智能的负载均衡可以尽可能地将请求的流量限制在一个空间里面,这就可以改善性能(降低延迟)并节省系统整体的开销(减少跨区域的带宽和光纤需求)。

负载均衡器 vs 代理服务器

其实在业界里面,在谈起网络负载均衡的时候,负载均衡器和代理服务器这两个词的用法是大致等同的(严格地说,并非所有代理服务器都是负载均衡器,但是多数代理服务器的主要功能里面都有负载均衡)。

可能有人会这样反驳,有些负载均衡流程是通过一个在客户端内置的类库来完成的,这种负载均衡器就不能说是代理服务器。不过我认为区分这种特例会给对这一本来含混的话题带来不必要的复杂性。我们会在后面讨论一下这种类型的负载均衡器,但本文只会把这类内置的负载均衡拓扑结构看作代理服务器的一个特例 - 从整体抽象的视角来看,一个应用进程使用内置的能起到代理作用的类库,跟使用外部的负载均衡器是一样的。

L4(连接 / 会话) 负载均衡

现在业界的负载均衡方案可以分为两种:L4 和 L7,分别所指的是 OSI 模型里面的第 4 层和第 7 层。不过我觉得使用这两个分类其实有点不对,其原因在介绍 L7 负载均衡的时候会是显然的。OSI 模型其实并不能很好地描述那些既涉及到第 4 层协议(如 TCP、UDP)又使用了其他层的协议的复杂负载均衡方案。比如说,一个 L4 的 TCP 负载均衡在给 TLS 终端(TLS termination)提供了支持的情况下,是否又应该算是 L7 负载均衡器呢?

图 2:L4 TCP 终端负载平衡
图 2:L4 TCP 终端负载平衡

图 2 展示了一个传统的 L4 TCP 负载均衡器。在这种情况下,客户端会向负载均衡器建立 TCP 连接,然后负载均衡器会截掉这个连接(也就是直接响应 SYN 报文),选择一个服务端,然后跟相应服务端建立新的 TCP 连接(即发送一个新的 SYN 报文)。 这张图的一些的细节现在并不重要,我们会在后续专门讲 L4 负载均衡的部分再详细讨论。

L4 负载均衡器通常只会操纵第 4 层里面的 TCP/ UDP 的连接或会话。粗略地说,这种负载均衡器所做的只是把一些字节转到另外一个地方,并确保同一会话的字节数据会转到同一个服务端。L4 负载均衡器对它所操纵的字节的应用细节是一无所知的。这里所说的字节数据可以是 HTTP 的、或者是 Redis、MongoDB,甚至是其他应用层协议的。

L7(应用)负载均衡

L4 负载均衡的技术简单,目前仍有广泛用途。那么 L4 负载均衡有什么局限性使得我们必须关注 L7(应用)负载均衡呢?下面就介绍一个 L4 负载均衡的使用场景:

  • 两个 gRPC / HTTP2 客户端想要通过一个 L4 负载均衡器跟服务端交互
  • L4 负载均衡器为每一个传入 TCP 连接都创建了一个传出 TCP 连接,结果就有了两个传入和传出连接
  • 然而,其中一个客户端 A 会每隔 1 分钟发 1 个请求(1 RPM),另一个客户端 B 则会每秒发 50 个请求(50 RPS)。

在这个情景里面,被选定处理客户端 A 的请求的服务端就所承担的负载就会是客户端 B 所对应的服务端的 3000 倍!这个问题很大,从根本上破坏了负载均衡的初衷。不得不提,这一问题会经常出现在一些引入了复用(Multiplexing)和持久化连接(Kept-alive)的协议里面(复用指的是并行地向往一个第 4 层的连接发送多个应用请求,持久化连接指的就是在没有正进行的请求时也不关闭连接)。出于效率上的考虑,所有现代的网络协议都引入了复用和持久化连接的特性(建立连接的性能开销通常很大,尤其是在连接要被 TLS 加密的时候),因此 L4 负载均衡器的负载不均衡问题也就会变得越来越显著。L7 负载均衡器则可以解决这个问题。

图 3: L7 HTTP/2 截止负载平衡
图 3: L7 HTTP/2 截止负载平衡

图 3 展现了一个 L7 HTTP/2 的负载均衡器。此时,客户端会向负载均衡器建立一个 HTTP/2 TCP 连接,然后负载均衡器会再跟两个服务端建立连接。在客户端向负载均衡器发送两个 HTTP/2 数据流的时候,1 号流会被发送到 1 号服务端,2 号流会被发到 2 号服务端。这样,即便一个复用客户端发来了大量不同的请求,这些请求带来的负载也最终会高效地分发给各个服务端。这也是 L7 负载均衡对现代网络协议的一大意义(L7 负载均衡器还可以检查应用层流量的具体内容。这会额外带来不少好处,不过我们之后再说)。

L7 负载均衡和 OSI 模型

正如我在介绍 L4 负载均衡时所说的,用 OSI 模型来描述负载均衡会有很多问题。这原因就在于 OSI 模型的第 7 层本身在负载均衡的视角来看就又会分为好几个抽象层。比如对 HTTP 协议就又可以分为以下子层:

  • 可选的传输层安全协议(TLS)。这里要指出,在计算机网络领域里面 TLS 该算 OSI 模型的哪一层的问题依然存在争议。不过为了方便讨论,本文会将其放在第 7 层。
  • 物理意义上的 HTTP 协议(HTTP/1 或 HTTP/2)
  • 逻辑意义上的 HTTP 协议(首部、正文还有尾部等)
  • 消息协议(gRPC、REST 等)

一个成熟的 L7 负载均衡器会为每一个子层提供对应的功能。另外一些 L7 负载均衡器则可能只会有一小部分能算在第 7 层的功能。总而言之,L7 负载均衡器比 L4 的会具有更多更复杂的功能(这里只提到了 HTTP 协议,实际上 L7 负载均衡还给很多其他应用层的协议带来了好处,比如 Redis、Kafka,还有 MongoDB 等)。

负载均衡器的功能

这一部分是对负载均衡器所提供的高层功能的一个总结。不过并不是所有负载均衡器都会提供全部功能。

服务发现

服务发现指的是负载均衡器确认一个可用的服务端集合的流程。实现的具体方法有很多,比如:

健康检查

健康检查指的是负载均衡器确认某个服务端是否能正常接受传入流量的流程。这一流程通常又分为两种执行方式:

  • 主动方式:负载均衡器每隔一段固定时间就给服务端发一个 ping(例如给服务端的 /healthcheck 端点发一个 HTTP 请求),以此确认服务端的可用状态。
  • 被动方式:负载均衡器会从主要的数据流里面检测服务端的可用状态。比如一个 L4 负载均衡器可以在某个服务端连续出现 3 个连接错误的时候认为它是不可用的;一个 L7 负载均衡器可以在服务端连续出现 3 个 HTTP 503 响应的时候认为它是不可用的。

负载均衡

负载均衡器必须脚踏实地地实现负载均衡,没毛病!不过,给定一个可用的服务端集合,又如何挑选一个服务端来接受连接或者请求呢?负载均衡的算法是个活跃的研究领域,具体例子有简单的随机选择或轮转调度,乃至十分复杂的,会考量时延和服务端当前负载的算法。现在最流行的算法是 power of 2 least request load balancing,兼顾了性能和简洁方面的需要。

会话粘附

在一些应用里面,让同一会话的请求能到达相同的服务端是很重要的。这会影响到对缓存以及复杂的临时状态的维护。对会话的定义又可能会写在 HTTP cookies、客户端连接属性或者别的参数上。很多 L7 负载均衡器都对会话的粘附提供了一定的支持。不过,我想指出会话粘附其实是很难维持的(主管特定会话的服务器会随时挂掉),因此在设计面向会话的系统时应该多加谨慎。

TLS 终端

TLS,以及 TLS 在边缘服务,还有保护服务间通信中的角色这些话题,都值得再写一篇文章来探讨。很多 L7 负载均衡器都为 TLS 做了很多处理,包括实现连接截止、整数校验及绑定,使用 SNI 提供证书等等。

可观测性

互联网自古以来就是不可靠的,而负载均衡器经常要负责输出状态、跟踪还有日志以便运维人员能观测系统,定位错误,并解决问题。我时常会 “可观测性,可观测性,可观测性” 地念叨,而负载均衡器的输出里面可以观测到的东西是各种各样的。最先进的负载均衡器会提供多种输出,包括数字状态、分布式系统的跟踪,还有自定义的日志等。我想指出这种可观测性的改善并非一蹴而就的,负载均衡器需要额外付出一些代价才能做到这点。不过,可观测数据带来的好处大大地超出了其在性能上的开销。

安全性及 Dos 防御

负载均衡器常常会采取一些安全功能,比如流量限制、身份认证,以及防 Dos (拒绝服务攻击)措施(比如记录并识别 IP 地址,以及过滤等技术)等。在边缘代理拓扑里面安全性会更受重视,后面会提到。

配置与控制层

负载均衡器需要配置。在一个大的部署体系里面,配置更是极其重要的部分。通常,配置负载均衡器的系统会被叫做 “控制层”,且有很多种实现形式。我在服务网格数据层 vs 控制层这篇博客里面谈到了关于这话题的更多细节。

还有很多别的功能

这一部分只提了负载均衡器功能的一点皮毛。在详细介绍 L7 负载均衡器的部分还会谈到更多种类的功能。

负载均衡器拓扑结构的种类

现在我们已在较高层面上大致见识了负载均衡器是什么、L4 和 L7 负载均衡器的区别,以及对其功能的一个总结。接下来我会介绍各种分布式系统里面负载均衡器部署的拓扑结构。(下面每个拓扑结构都适用于 L4 和 L7 负载均衡器的情景)

中介代理服务器

图 4:中介代理拓扑
图 4:中介代理拓扑

图 4 所给出的中介代理服务器拓扑结构应该会是最为读者所熟知的负载均衡方案。这一分类涵盖了如 Cisco、Juniper、F5 等硬件设备;还有像亚马逊的 ALB 和 NLB 以及谷歌的 Cloud Load Balancer 等这些云端的软件解决方案;还有像 HAProxyNGINX 以及 Envoy 这样的纯粹的通过软件来自行搭建并主管的解决方案。中介代理拓扑的好处便是其对用户的简洁性。总的来说,用户通过 DNS 连接到负载均衡器即可使用,不需理会其他细节。不过这一方案有不少坏处,便是代理服务器(即便做成一个集群)不仅会造成单点故障的情形,还会成为扩展的瓶颈。同时,中介代理这一黑盒的存在也会让操作变得困难,使得我们很难查清发生的问题是否有出现在客户端、物理网络、中介代理,还是服务端。

边缘代理服务器

图 5:边缘代理拓扑
图 5:边缘代理拓扑

图 5 所给出的边缘代理服务器拓扑结构其实只是中介代理拓扑的一种变体。这一模式下的负载均衡器可以通过互联网访问。在这种情况下,负载均衡器通常必须提供一些 “API 网关” 的功能,比如说 TLS 终端、流量限制、身份认证,以及复杂的流量路由功能。边缘代理拓扑的好处和坏处跟中介代理拓扑一样。顺便一提,在构建一个面向互联网的分布式系统时,边缘代理会是一个绕不开的部分,而客户端通常要使用服务提供者不能干预的网络库来通过 DNS 访问这一系统(使得在客户端上直接运行客户端集成类库或者边车代理拓扑显得很不实用)。除此之外,出于安全考虑,我们应该准备一个接收所有从互联网进入到系统里面的流量的网关。

客户端嵌入类库

图 6:通过嵌入到客户端的类库进行负载均衡
图 6:通过嵌入到客户端的类库进行负载均衡

为了规避中介代理拓扑的单点故障,以及扩展瓶颈这些问题,很多复杂的底层结构都以类库的形式直接迁移到了一个嵌入到客户端里面的负载均衡器里面,如图 6 所示。目前有很多类库支持各种各样的功能,不过最为熟知、功能最丰富的还是 FinagleEureka / Ribbon / Hystrix,以及 gRPC(对一个内部的叫 Stubby 的谷歌系统有着松散的依赖)。这一方式的好处主要是其将负载均衡器的职能完全分发给了每个客户端,消灭了上面提到的单点故障以及扩展方面的问题。这一方式的坏处主要是这一基于类库的解决方案其实必须在每一种可能用到的编程语言里面都实现一遍。分布式系统的架构也会因此 “通晓” 越来越多门编程语言。在这种环境里,在多种编程语言里面实现网络库的成本也会变得让人望而却步。最终,在一个大型服务架构里面部署一个类库的更新会经受极大的痛苦,很可能会让生产环境同时运行好几个不同版本的类库,并让开发及运维成本激增。

总而言之,上述提到的类库方案在能限制编程语言扩展,并克服类库更新的阵痛的企业里面还是很成功的。

边车代理服务器

图 7:通过边车代理进行负载均衡
图 7:通过边车代理进行负载均衡

图 7 所示的边车代理服务器(Sidecar proxy)就是客户端嵌入库的一种变体。最近,这种拓扑结构又因 “服务网格(service mesh)” 的出现而流行。边车代理背后的原理是以牺牲跳转到别的进程的一点延迟为代价,以实现一种无需适配特定编程语言的客户端集成类库方案。目前最流行的边车代理有 EnvoyNGINXHAProxy 还有 Linkerd。若想了解边车代理方案的更多细节,不妨看看我的这篇介绍 Envoy 的博客,以及这篇主题为服务网格面板 vs 控制层的博客。

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

  • 中介代理拓扑是最容易使用的负载均衡模式。然而由于单点故障、扩展瓶颈还有黑箱操作这写因素的存在,这一模式并不算太好。
  • 边缘代理拓扑跟中介代理拓扑类似,不过它在面向互联网的分布式系统架构里通常是绕不开的。
  • 客户端集成类库拓扑的性能以及可扩展性是最好的,但受限于其类库必须在每种客户端语言中实现一遍,且需要每个客户端都要更新类库。
  • 边车代理拓扑的性能比客户端集成类库要差一点,但可以不受语言还有更新的限制。

总的来说,我认为在服务间的通信里面,边车代理拓扑(服务网格)会逐渐地取代其他的拓扑结构。另外,为了处理传入服务网格的互联网流量,边缘代理拓扑会长期存在。

目前 L4 负载均衡的水平

L4 负载均衡器还有用吗?

本文已讨论了 L7 负载均衡器对现代网络协议的不少好处,并且也会在之后的部分详细讲解 L7 负载均衡器的各种功能。这是否在说 L4 负载均衡器没用了呢?不是!尽管我认为 L7 负载均衡器会最终在服务间通信里面完全取代 L4 负载均衡器,但 L4 负载均衡器在边缘部分依然极其重要,因为几乎所有现代的大型分布式架构都会为处理互联网流量而使用一种双层式的 L4 / L7 负载均衡架构,而在边缘部署部分的 L7 负载均衡器前面专门部署 L4 负载均衡器有着这些好处:

  • 各种 L7 负载均衡器会持续执行很多复杂的分析、变换还有应用层流量的路由操作,在有一个 L4 负载均衡器的前提下它们就可以只在传入流量负载(测量的指标有每秒数据包数和每秒字节数)里面接受并处理跟这个优化的 L4 负载均衡器相对较少的一部分。这就让 L4 负载均衡器成了一个能更好地应对特定类型的 Dos 攻击(如 SYN 洪泛、各种数据包的洪泛攻击等)的位置。
  • L7 负载均衡器的部署往往会更加频繁,且往往比 L4 的有更多 BUG。在 L7 负载均衡器之前设置一个 L4 负载均衡器就可以在 L7 负载均衡器进行部署的时候进行健康检测还有 draining。这比部署一个基于现代的 L4 负载均衡器(通常会使用 BGP 和 ECMP,下文会提到)的机制要简单的多。此外,因为 L7 负载均衡器的功能更为负载,会更有可能出现 BUG,有个 L4 负载均衡器挡在前面也能让流量能确实地绕开异常或故障的服务端,达到稳定整体系统的目的。

在本章接下来的部分,我会介绍一些关于基于中介 / 边缘代理的 L4 负载均衡器的一些不同设计。这些设计是没办法套用到客户端集成类库还有边车代理拓扑里面的。

TCP / UDP 终端负载均衡器

图 8:L4 终端负载均衡器
图 8:L4 终端负载均衡器

第一种仍在使用的 L4 负载均衡器便是图 8 所示的终端负载均衡器。这跟在此前介绍 L4 负载均衡器的部分所介绍的负载均衡器是一样的。这种负载均衡器会用到两种类型的 TCP 连接:一个连接了客户端,另一个连接了服务端。

L4 终端负载均衡器现在仍在使用的原因有两点:

  1. 实现这种类型相对简单。
  2. 对距离较近(延迟低)的客户端的连接截止能持续地改善性能。具体地说,如果有个负载均衡器能尽可能地靠近处于一个松散网络(比如蜂窝网络)里的客户端,那么在使用可靠的光纤传输来把数据重定向到其最终的目的地之前的重传过程就可以进行得更快。也就是说,这种负载均衡器可以用在入网点(Point of presence,POP)这一使用场景里面来进行原始 TCP 连接的截止。

TCP / UDP 透传负载均衡器

图 9:L4 透传负载均衡器
图 9:L4 透传负载均衡器

第二种要介绍的 L4 负载均衡器便是如图 9 所示的透传负载均衡器。这种负载均衡器不会截止 TCP 连接,而会在进行连接追踪以及网络地址转换(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 的负载均衡器。负载均衡器就会把 TCP 报文的目标地址还有端口号改成 10.0.0.2:9000,并且还会把源地址和端口号换成 1.2.3.4:80。这样在服务端响应 TCP 连接的时候,服务端发出的报文会返回到负载均衡器,负载均衡器就可以进行连接追踪还有 NAT 了。

为什么这一更复杂的负载均衡器能取代之前提到的终端负载均衡器呢?有几点原因:

  • 性能及资源开销:由于透传负载均衡器不用截止 TCP 连接,它们便不用缓存任一 TCP 连接的发送或接收窗口了,而连接追踪存储的每个连接的状态其实只占很小空间,且通常能通过高效的哈希表查询来访问。因为这点,透传负载均衡器往往能比终端负载均衡器在规定时间内持续处理更大数目的 TCP 连接以及数据包。
  • 让服务端可以进行自定义的拥堵控制:通过 TCP 拥堵控制机制,互联网里的各个节点就能限制发送数据的速度,以防压垮链路的带宽和路由器的缓存。由于透传负载均衡器并没有截止 TCP 连接,它不会参与到拥堵控制里面,使得服务端可以根据各自的应用场景使用不同的拥堵控制算法。这也让改变拥堵控制方案的测试变得容易(比如最近 BBR 的首次试验)。
  • 为服务器直接返回方式(DSR)还有集群化 L4 负载均衡提供了基础:透传负载均衡对像 DSR 还有基于分布式一致散列算法的集群,还有 DSR 这样的更先进的 L4 负载均衡方案是不可或缺的一部分。

服务器直接返回

图 10:服务器直接返回(DSR)负载均衡器
图 10:服务器直接返回(DSR)负载均衡器

图 10 展示了服务器直接返回(DSR)负载均衡器。DSR 建立在上面提到透传负载均衡器之上,对经过负载均衡器的传入 / 请求数据包的处理做了优化。采取 DSR 这一模式的主要原因在于很多响应的流量都比请求的流量要大得多(比如典型的 HTTP 请求 / 响应模式)。不妨假设总流量的 10% 是请求流量,90% 是响应流量,如果负载均衡器引入了 DSR,那么负载均衡器的理论容量只需要达到总流量的 1 / 10 便可以满足系统需求了。这一优化会给系统成本及可靠性方面(多一事不如少一事)带来持久的好处,毕竟负载均衡器在以往看来都是极其昂贵的。

DSR 负载均衡器基于以下方式扩展了透传负载均衡器的概念:

  • 负载均衡器依然会执行 “部分的” 连接跟踪。在相应数据包不会经过负载均衡器的前提下,负载均衡器是不会观测到完整的 TCP 连接状态的。不过,负载均衡器还是可以从客户端发送的数据包以及空闲超时的计时器里推出一些状态的。
  • 负载均衡器不会再用 NAT,而是会用一种通用路由封装(Generic Routing Encapsulation,GRE)技术来包装发给服务端的 IP 数据报。在服务端设备收到包装过的数据报时,它就可以对其拆包得到客户端的源 IP 地址还有端口号了。这就让服务端可以直接给客户端发送响应,响应数据包的流量也不会流经负载均衡器。
  • DSR 负载均衡器还有一个重要因素,那便是服务端也参与到了负载均衡器里面。服务端本身就需要一个配置好的 GRE 隧道,并且需要依靠

不论是透传的还是 DSR 的负载均衡器,都有多种多样的在负载均衡器和服务端间实现连接追踪、NAT、GRE 等要素的方法。不过这一话题的讨论就超出了本文的范围了。

通过高可用配对方式实现容错

目前为止,我们已经分别探讨了一些 L4 负载均衡器的设计。其中透传的和 DSR 的负载均衡器都需要保存一些连接追踪及其自身的状态。那要是负载均衡器瘫痪了该怎么办?在这种情况下,经过这个负载均衡器的所有连接都会受到严重影响,同时视具体应用而定也会对应用性能造成持续的冲击。

图 11:通过 HA 配对和连接追踪的 L4 容错
图 11:通过 HA 配对和连接追踪的 L4 容错

从前,L4 负载均衡器其实是一些熟知的供应商(Cisco、Juniper、F5 等)出售的硬件设备。这些设备可以处理大额的流量,价格也极其高昂。为了避免一个负载均衡器的瘫痪影响到所有的连接并导致应用持续停运,负载均衡器通常都部署在一个如图 11 所示的高可用配对里面。在其中较典型的 HA 负载均衡器体系的设计如下:

  • 有一对 HA 边缘路由器会提供一些虚拟的 IP 地址(VIP)。这些边缘路由器会通过边界网关协议(BGP)来声明这些 VIP。其中一个主边缘路由器具有比备份的路由器高的 BGP 权重,因此它也会在一般情况下维护全部连接。(BGP 是个极其复杂的协议,出于阅读本文的需要,我们只需要把 BGP 想成一个设备向网络宣布它可以接受其他设备发过来的流量,并且每个链路都会有一个影响流量传导优先级的权重的机制即可)
  • 同样,主 L4 负载均衡器会向边缘路由器宣布一个比其备份更高的 BGP 权重,使其在一般情况下承载全部流量。
  • 主负载均衡器会交叉连接到其备份,并共享全部的连接追踪状态。这样,在主负载均衡器宕机时,其备份也可以接管处理全部的尚存连接。
  • 两个边缘路由和两个负载均衡器也会交叉相连。这就意味着在一个边缘路由或是负载均衡器宕机时,或者 BGP 广播由于各种原因被撤回了,剩下的备份依然可以接管所有流量。

上述体系便是很多现在的高流量互联网应用都在使用的一种模式。不过,上述体系也存在这些固有的缺点:

  • 如果一个 VIP 的流量超出了一个 HA 配对的容量,那么 VIP 就需要在多个 HA 负载均衡器配对里面正确地划分成多个 VIP。
  • 系统资源的利用率低下。在一般情况下还会有 50% 的闲置容量。鉴于以前的硬件负载均衡器极贵,负载均衡器的闲置成本也是很高的。
  • 这一活动 / 备份模式已不能满足现代分布式系统的设计对差错容忍的需要。比如,一个系统应该能经受多重同时的故障并依然能保持运行,而 HA 负载均衡器易受活动设备和备份设备的整体同时故障的影响。
  • 服务商专卖的大型硬件设备的价格高昂,并且会带来对服务商的依赖。一般来说,把硬件设备换成一些使用商业计算服务器来构建的可水平扩展的软件解决方案会更好。

通过分布式一致性散列算法实现容错及扩展

图 12:通过负载均衡器集群和一致性散列算法的 L4 容错及扩展
图 12:通过负载均衡器集群和一致性散列算法的 L4 容错及扩展

上一部分介绍了使用 HA 配对的 L4 负载均衡器的差错容忍模式以及它的一些设计上的局限。大概在 2000 年之后,一种如图 12 所示的大型并行 L4 负载均衡系统开始了设计,并在一些大型的互联网底层设施里面得到了部署。这些系统的目标在于:

  • 解决 HA 配对设计带来的所有问题
  • 摆脱对服务商专门提供的硬件负载均衡器的依赖,转向使用基于标准计算服务器以及网卡配合商业软件所构建的方案

这种 L4 负载均衡器的设计便是本部分所说的 “通过分布式一致性散列算法实现容错及扩展”。它的工作模式如下:

  • 有 N 个边缘路由器会以同一 BGP 权重声明全部任播的 VIP,同时使用等价多路径路由(Equal-cost multi-path routing,ECMP)来确保一个数据流(flow)的所有数据包会抵达同一个边缘路由。一个数据流通常可以用一个记有源 IP、源端口、目标 IP、目标端口的四元组来表示(简单地说,ECMP 就是一种在一些等权重的网络链路上使用一致性散列算法来分发数据包的方式)。尽管边缘路由器本身并不会特别关注哪个数据包从哪来,但一般来说我们会更希望一个数据流里面的全部数据包能经过同一群链路,这样也可以避免数据包的失序带来的性能影响。
  • 有 N 个 L4 负载均衡器会以同一 BGP 权重声明全部 VIP 并广播给边缘路由器,边缘路由器也会在一般情况下基于 ECMP 来选择同一个负载均衡器来承载同一数据流。
  • 每个 L4 负载均衡器都会执行部分的连接追踪,然后使用一致性散列算法来选择一个服务端来接收数据流。这里也会先用到 GRE 来包装数据报,然后再将包装的数据报发给服务端。
  • 服务端在这里也会使用 DSR 模式直接将响应数据包经由边缘路由器发给客户端。
  • L4 负载均衡器所实际使用的一致性散列算法也是一个热门的研究领域。总的来说,这一算法要平衡负载分配均衡化、延迟最小化、后端更新成本最小化,还有内存开销最小化这些因素。对这一话题的讨论也超出了本文的范围。

我们再来看看上述设计是怎么解决 HA 配对方案所带来的问题的。

  • 边缘路由器还有负载均衡器可以按需增加。一致性散列算法在每一层的使用减少了设备增加时受影响的数据流的数目。
  • 边缘路由器和负载均衡器都可以使用商业硬件来部署,而硬件成本降到了传统的硬件负载均衡器的一小部分(下面会详述)。

针对这一设计有一个经常会问到的问题:“边缘路由器为什么不能直接使用 ECMP 来跟服务端交互呢?我们还要负载均衡器干嘛?”。这其中的原因主要围绕着 Dos 防御以及服务端的易操作性两个方面。如果没了负载均衡器,那么每个服务端都要参与到 BGP 协议的体系里来,这样在执行滚动部署的时候就会很让人难堪了。

所有现代的 L4 负载均衡系统其实都在朝着这种设计(或其变体)发展。有两个最为突出并熟知的例子是谷歌的 Maglev 还有亚马逊的 Network Load Balancer。目前还没有哪个开源的负载均衡器实现了这种设计,不过据我所知有间公司正在计划在 2018 年发布一个这样的负载均衡器。我很热切地期待着它的发布。它将会成为现代 L4 负载均衡器在开源领域的最后一块拼图。

目前 L7 负载均衡的水平

The proxy wars in tech currently is quite literally the proxy wars. Or the "war of the proxies". Nginx plus, HAProxy, linkerd, Envoy all quite literally killing it. And proxy-as-a-service / routing-as-a-service SaaS vendors raising the bar as well. Very interesting times! 目前在技术领域的代理服务器之战(proxy wars in tech)就如同其名字 “代理人战争(proxy wars)” 一样。Nginx plus、HAProxy、Linkerd,还有 Envoy 都身处这一战场,还有代理即服务 / 路由即服务的 SaaS 服务商也拉高了这一战局的水准。这时代太有意思了!

确实是这样。在近几年里,L7 负载均衡器 / 代理服务器的发展迎来了一次复苏。微服务架构还有分布式系统的发展更是进一步推动了这一发展。从根本上来说,网络的不可靠本质让其在被频繁使用的时候降低了不少操作效率。在另一方面,自动扩展、容器调度器等新事物的发展使得在静态配置文件里面规定静态 IP 的配置方式也已经落后于时代了。系统不仅需要更高效地利用网络,还需要更高的动态性,更向负载均衡器提出了更高的功能性需求。在这一部分里面我会简单地总结现代 L7 负载均衡器所发展出来的一些功能。

网络协议支持

现代的 L7 负载均衡器给很多不同的网络协议都提供了显式的支持。负载均衡器对应用层流量了解的越多,它能在可观测数据的输出、高级负载均衡操作以及路由等方面执行更为复杂的操作。比如目前 Envoy 就对 HTTP/1、HTTP2、gRPC、Redis、MongoDB 还有 DynamoDB 这些 L7 的协议的解析以及路由提供了显式的支持。将来 Envoy 可能会支持更多的协议,比如 MySQL 还有 Kakfa。

动态配置

如上文所述,分布式系统中的动态性需求与日倍增,需要开发一个动态的、响应式的控制系统来配合工作。Istio 就是其中的一个典例。不放阅读一下我的服务网格面板 vs 控制层这篇文章来了解关于这话题的更多信息。

高级负载均衡

现在 L7 负载均衡器基本都内置了对一些高级的负载均衡方法的支持,比如超时、重试、限流、断路、投影(shadowing)、缓冲、基于内容的路由等等。

可观测性

在介绍负载均衡器通用功能也提过,动态系统的与日俱增也增加了调试的难度。稳健的、可观测性强的协议细节输出大概也是了现代 L7 负载均衡器所提供的最重要的一个功能。所有的 L7 负载均衡解决方案都在某种程度上要求了生成数据统计、分布式追踪,还有自定义日志这些功能。

可扩展性

现代 L7 负载均衡器的用户时常会想要给负载均衡器增加一些自定义的功能。这可以通过编写一个插件式的过滤器并加载到负载均衡器里面来实现。很多负载均衡器都支持这一编写脚本(通常用 Lua 来编写)的特性。

容错性

我在上面提到了很多有关 L7 负载均衡器进行差错容忍的方式。那么 L7 负载均衡器又如何进行差错容忍呢?总的来说,我们可以认为 L7 负载均衡器具有可扩展性和无状态性。商业化软件的使用让 L7 负载均衡器能更容易地进行水平扩展。另外,L7 负载均衡器所执行的处理还有状态追踪要比 L4 的要复杂得多,给 L7 负载均衡器构建一个 HA 配对在技术上是可行的,但任务会非常艰巨。

总而言之,在 L4 和 L7 负载均衡技术的领域里面,整个业界都在逐渐脱离 HA 配对的模式,并朝着使用可水平扩展并能用一致性散列算法来聚合的系统的方向发展。

还没完

L7 负载均衡器现仍在以惊人速度演变着。不妨在 Envoy 的架构概览里面看一看 Envoy 所提供的一些新特性。

全局负载均衡及集中的控制层

图 13:全局负载均衡
图 13:全局负载均衡

谈及负载均衡的未来,单个负载均衡器有着成为商业化设备的趋势。在我看来,其中所有的创新和商业机遇都埋藏在控制层里面。图 13 就展示了一个全局负载均衡系统的例子。此例有这些不一样的要素:

  • 每个边车代理都和三个处在不同空间(A、B、C)内的服务端交互。
  • 90% 的流量会被传到 C 空间,而 A、B 空间则各自承受 5%。
  • 边车代理和后端会向全局负载均衡器定期报告状态。这就让后者可以根据延迟、成本、负载还有目前的故障情况来进行决策。
  • 全局负载均衡器会定期地给每一个边车代理设置目前的路由信息

另外,全局负载均衡器也会逐渐能做一些单个负载均衡器无法完成的复杂任务。比如:

  • 自动探测并绕开故障部分
  • 执行全局安全及路由策略
  • 使用机器学习和神经网络探测并消除异常流量(如 DDoS 攻击)
  • 提供能让工程人员在整体上了解并操作分布式系统的集中可视化 UI

为了让全局负载均衡成为可能,用作控制层的负载均衡器必须具有能进行复杂动态配置的能力。不妨也查阅一下我的 Envoy 的通用数据层 API 还有服务网格数据层 vs 控制层来了解关于这话题的更多信息。

从硬件到软件的演变

目前本文只是主要在介绍老式的 L4 负载均衡器 HA 配对模式的时候提了一下硬件 vs 软件这一话题,而这一方面的业界趋势又是怎么样的呢?

I've seen the new OSI stack of eight layers of software. I think it's more like this:

我已经看过新的 OSI 八层模型了。

我觉得它更像是这样:

—— @infosecdad

图 14:推文配图
图 14:推文配图

上面这条推文虽然是一种夸张式的幽默,但其实也是对趋势的一个很好的总结,那就是:

  • 从前,路由器和负载均衡器都是作为一种极其昂贵的专卖硬件来提供的。
  • 后来,很多专卖的 L3 / L4 网络设备都逐步被商业化的服务器硬件、网络适配器以及建立在其上的像 IPVSDPDK 还有 fd.io 这样的框架的软件方案所取代。现在,一台在数据中心里不到 $5K 的机器就可以使用 Linux 和一个用 DPDK 编写的自定义用户空间应用来轻松地饱和利用 80Gbps 的网络适配器。与此同时,能以惊人的总带宽和包速率进行 ECMP 路由的便宜的基础路由器 / 交换机的 ASIC 核心也被打包成了商业化的路由器。
  • 像 NGINX、HAProxy 还有 Envoy 这些复杂的 L7 软件负载均衡器也在快速地改进并开始侵占像 F5 这样的供应商在之前所独占的领域。因此,L7 负载均衡器也在朝着商业化软件解决方案的方向快速发展。
  • 与此同时,受主要的云服务供应商的带动,业界整体也在朝着 IaaS、CaaS 以及 FaaS 发展。这也就意味着在以后只有很小一部分工程师才需要了解物理网络的工作方式(也就是上图的 “black magic” 和 "something we no longer need to know squat about" 部分)。

负载均衡现况及前景总结

本文要点如下:

  • 负载均衡器是现代分布式系统中的关键部分。
  • 负载均衡器主要有两个分类:L4 和 L7。
  • L4 和 L7 负载均衡器在如今依然各有用处。
  • L4 负载均衡器在朝着可水平扩展的一致性散列算法解决方案发展。
  • 由于与日俱增的动态微服务架构需求,L7 负载均衡器在如今被大量使用。
  • 全局负载均衡以及控制层和数据层的分离是负载均衡的一个未来方向,并且也是未来的多数创新和商业机遇所埋藏的地方。
  • 业界正朝着商业化开源硬件及软件的网络解决方案发展。我相信像 F5 这样的传统的负载均衡服务商会是第一批被开源软件和云服务供应商所取代的角色;像 Arista、Cumulus 这样的传统路由器 / 交换机供应商在特定部署情况下也尚有一席之地,但最终也会被公共云服务供应商及其物理网络所取代。

总之我认为,现在正是计算机网络发展的一个精彩时期!面向多数系统及开源的软件正以极快步伐进行着发展,并且随着分布式系统不断通过 “无服务器化” 规范向动态化前进,底层网络还有负载均衡系统的复杂度还会继续增加。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 网络负载均衡和代理服务器是什么?
    • 负载均衡器 vs 代理服务器
      • L4(连接 / 会话) 负载均衡
        • L7(应用)负载均衡
          • L7 负载均衡和 OSI 模型
          • 负载均衡器的功能
            • 服务发现
              • 健康检查
                • 负载均衡
                  • 会话粘附
                    • TLS 终端
                      • 可观测性
                        • 安全性及 Dos 防御
                          • 配置与控制层
                            • 还有很多别的功能
                            • 负载均衡器拓扑结构的种类
                              • 中介代理服务器
                                • 边缘代理服务器
                                  • 客户端嵌入类库
                                    • 边车代理服务器
                                      • 负载均衡器拓扑结构的优缺点总结
                                      • 目前 L4 负载均衡的水平
                                        • L4 负载均衡器还有用吗?
                                          • TCP / UDP 终端负载均衡器
                                            • TCP / UDP 透传负载均衡器
                                              • 服务器直接返回
                                                • 通过高可用配对方式实现容错
                                                  • 通过分布式一致性散列算法实现容错及扩展
                                                  • 目前 L7 负载均衡的水平
                                                    • 网络协议支持
                                                      • 动态配置
                                                        • 高级负载均衡
                                                          • 可观测性
                                                            • 可扩展性
                                                              • 容错性
                                                                • 还没完
                                                                • 全局负载均衡及集中的控制层
                                                                • 从硬件到软件的演变
                                                                • 负载均衡现况及前景总结
                                                                相关产品与服务
                                                                负载均衡
                                                                负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                                                                领券
                                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档