公司使用 AWS,最近线上出现一次故障和 AWS Network Load Balancer 相关,借机了解 Network Load Balancer 的工作原理,于是发现了 Envoy 的这篇文章,让我对负载均衡有了一个系统的了解,在征得作者同意后,翻译了一下(省略了一些认为不太重要的章节),希望也对你有所帮助。
原文地址:Introduction to modern network load balancing and proxyingblog.envoyproxy.io/introduction-to-modern-network-load-balancing-and-proxying-a57f6ff80236什么是负载均衡和代理?
Wikipedia 是这么定义的:
在计算世界中,负载均衡通过使用多个计算资源来提高负载的分布。计算资源包括计算机,计算集群,网络链接,CPU,或者硬盘等。负载均衡的目标是优化资源的使用,最大化吞吐量,最小化响应延时,同时避免任何单一资源超载。负载均衡通过冗余,使用多个而不是一个组件提高可靠和可用性。负载均衡器通常包括专门的软件或者硬件,比如一个多层的交换机或者一个 DNS 服务进程。
以上定义适用所有各种计算,不仅仅是网络。操作系统使用负载均衡在物理处理器之间调度任务;容器编排系统(如 Kubernetes)使用负载均衡在计算集群之间调度任务;网络负载均衡器使用负载均衡在不同的后端实例调度网络任务。这篇文章接下来的部分只讨论网络负载均衡。
Figure 1: Network load balancing overview
Figure 1 显示了一个高度概括的网络负载均衡。Client 从 Backend 请求资源。负载均衡器位于 Client 和 Backend 之间,主要执行以下关键任务:
服务发现:哪些 Backend 在系统中是可用的?他们的地址是什么?(比如,负载均衡器如何与 Backend 通信?)健康检查:当前哪些 Backend 是健康的,可以接受请求的?负载均衡:使用什么算法在健康的 Backend 之间调度每一个请求?在分布式系统中,正确使用负载均衡有以下好处:
命名抽象:Client 不需要知道每一个 Backend 的地址(服务发现),只需要知道 负载均衡器的地址即可,而负载均衡器的地址可以通过 DNS 或者 IP:Port 的形式给出。容错:通过健康检查和各种算法,负载均衡器可以非常有效的避开故障或者过载的 Backend.成本和性能收益:分布式系统网络很少是同质的,通常是跨越多个网络分区。在一个分区内,网络通常是 undersubscribed。不同分区之间,oversubscribed 是常态。这里说的 over / sububscription指的是可通过 NIC 使用的带宽量占路由器之间可用带宽的百分比。智能的负载均衡可以尽可能把流量保持在一个分区内,这样可以增加性能(低延迟)和减少整体的系统成本(在分区之间需要更少的带宽和光纤)Load Balancer v.s. Proxy 负载均衡器和 Proxy 对比
当我们说到网络 Load Balancer 的时候,Load Balancer 和 Proxy 这两个词基本上是可以互换的。这篇文章里面也把这两个术语认为是相同的。(准确的讲,不是所有的 Proxy 都是 Load Balancer,但是大部分的 Proxy 都把负载均衡作为基本功能)。
L4(connection/session) load balancing 四层(连接/会话)负载均衡
当今业界讨论负载均衡,解决方案通常分为两类:L4 和 L7。这两个分类是指 OSI 模型下的 4 层和 7 层。其实,用 OSI 模型来归类负载均衡器不是特别合适。因为 OSI 模型很难覆盖 Load Balancer 的复杂性,一个 L4 的 Load Balancer 多少还会包含一些其他 OSI 层的协议。比如,一个 4 层的 TCP Load Balancer 也支持 TLS 连接,那它又是一个 L7 的 Load Balancer 了吗?
Figure 2: TCP L4 termination load balancing
Figure 2 展示一个传统的 4 层 TCP Load Balancer。一个 Client 向 Load Balancer 发起了一个 TCP 连接。Load Balancer 直接响应了 Client 的 SYN 请求,然后选择一个 Backend 并发起了 TCP 连接。 这个图的细节不重要,接下来的章节会详细说明。
这一部分的关键是说一个 4 层的 Load Balancer 通常只是操作 4 层 TCP/UDP 的连接或者会话。因此,4 层的 Load Balancer 基本上是在倒腾字节流,而且还要保证同一个会话的字节流流向同一个 Backend,而且 Load Balancer 完全不会感知到字节流的内容,这些字节流可能是HTTP、Redis、MongoDB 或者其他任何应用层协议。
L7(application) load balancing 七层负载均衡
4 层 Load Balancer 简单且应用广泛。那 4 层 Load Balancer 有什么缺点会让我们再搞一个 7 层 Load Balancer 出来呢?我们以一个 L4 的具体例子来说明:
两个 gRPC/HTTP2 Clients 想要跟一个 Backend 通信,他们通过一个 L4 Load Balancer 连接L4 Load Balancer 为每一个 Client 创建两个连接一进一出,共 4 条连接但是,Client A 每分钟发送 1 个请求;Client B 每秒发送 50 个请求上面的场景中,被 L4 Load Balancer 选中处理 Client B 的请求的 Backend 的负载会是被选中处理 Client A 的请求的 Backend 的负载的 3000 倍!这就是一个大问题了,完全违背了负载均衡的意义。值得注意的是,对于任何多路复用,保持连接的协议这些问题都是存在的。(多路复用即用一条连接发送所有的应用请求,保持连接即即使当前没有活跃的请求也不会断开连接)出于效率的原因,当前所有协议几乎都是多路复用且保持连接的(创建连接的成本是很高的,尤其是当连接还需要 TLS 加密的时候)。所以,L4 的这方面的劣势就明显了,而 L7 可以解决这个问题。
Figure 3: HTTP/2 L7 termination load balancingFigure 3 展示了一个 L7 HTTP/2 的 Load Balancer。Client 向 Load Balancer 发起一条 HTTP/2 TCP 连接。Load Balancer 后续建立了两个 Backend 连接。当 Client 向 Load Balancer 发送了两条 HTTP/2 Stream 的时候,Stream 1 被转发给 Backend 1,Stream 2 被转发给 Backend 2。这样,即使有不同负载的多路复用的 Client 也可以被有效的均衡到 Backend 上。这就是为什么 L7 的负载均衡对于现代协议这么重要。(由于需要探测应用层的流量,L7 的负载均衡也放弃了大量的好处,以下会详述。)
L7 Load balancing and the OSI model
就像在 L4 Load balancing 章节中提到的一样,用 OSI 模型描述 Load Balancing 的特性也是问题多多。理由就是 L7 本身就包含了 Load Balancing 抽象的多个分立的层。比如,对于 HTTP 流量,考虑以下子层:
可选的 TLS。网络界喜欢争论 TLS 到底属于 OSI 模型的哪一层。为了方便讨论,我们这里认为 TLS 是 L7物理上的 HTTP 协议 (HTTP/1、HTTP/2)逻辑上的 HTTP 协议(headers,body,trailers)消息协议(gRPC,REST 等)一个复杂的 L7 Load Balancer 可能会提供和任何一个子层都有关的特性。有些 Load Balancer 可能只会提供一个子集的特性。简而言之,从特性对比的视角来看,L7 Load Balancer 的场景分类是远比 L4 Load Balancer 复杂的多。
Load balancer features
这一节我们简要总结一下 Load Balancer 提供的高层特性。当然,并不是所有的 Load Balancer 都支持以下的特性。
服务发现 Service Discovery服务发现是指 Load Balancer 如何发现可用的后端,方法有很多,比如:静态配置文件、DNS、Zookeeper/Etcd/Consul 等
健康检查Health Checking健康检查是指 Load Balancer 如何知道哪些后端是健康可用,可以转发流量过去的。大体上归为两类:主动 — Load Balancer 主动定时向后端发送 Ping 命令来检测后端的是否健康被动 — Load Balancer 可以从数据流中检查后端的健康状况。对于 L4 的 Load Balancer,假如与后端有 3 次连接错误就认为是不健康的;对于 L7 的 Load Balancer,假如有三次 HTTP 503 返回码就认为不健康负载均衡 Load Balancing负载均衡算法属于研究的热门问题,从简单的如随机选择,轮询到复杂的如考虑到各种时延和后端负载的算法。考虑到性能和简洁性,最著名的算法之一是 power of 2 least request load balancing.粘性会话 Sticky Session对于某些特定的应用,同一个 Session 的请求始终转发到同一个后端是非常重要的。这可能和缓存,临时复合构建状态有关。这里说的 Session 包含的范围很广,可以是 HTTP cookies,client 连接或者其他的属性。很多 L7 负载均衡器已经支持粘性会话。另外,不得不说,粘性会话天生脆弱(因为处理会话的后端随时有可能会挂掉),所以,谨慎使用。TLS 中断 TLS Termination可观察性 Observability“可观察性,可观察性,可观察性”,重要的事情说三遍!网络本身就是不可靠的,而 Load Balancer 应该能输出统计数据,跟踪和日志等可以帮助运维人员搞清楚并修复可能出现的网络问题。Load Balancer 可观察性的输出范围很广泛。高级的 Load Balancer 都会提供非常丰富的输出,包括数据统计,分布式追踪和自定义Logging等。需要指出的是提高可观察性是有代价的,但是输出的统计数据的收益是远远大于微小的性能损耗的。安全和 Dos 防御 Security and DoS mitigation尤其是对于边缘部署的拓扑结构,Load Balancer 通过实现了各种安全特性,如限速,认证,DoS 防御(IP地址标准和识别,缓送技术等)配置和控制面板 Configuration and control panelLoad Balancer 需要是可配置的。在一个大型的部署中,这是一个非常重要的工作。通常把可以配置 Load Balancer 的系统称为『控制面板』。Load Balancer 的拓扑类型
我们已经大体上说了什么是 Load Balancer,L4 & L7 Load Balancer 的区别,并总结了 Load Balancer 的特性。接下来我们看一下在分布式系统拓扑结构中,Load Balancer 是如何部署的。(下面谈到的这些拓扑结构对 L4 & L7 都是适用的)。
中间代理Middle proxy
Figure 4: Middle proxy load balancing topology这种拓扑结构应该是大多数读者比较熟悉的一种。这个分类包括硬件设备(厂商有Cisco、Juniper、F5);云软件方案,比如 AWS 的 ALB & NLB 或者 Google 的 Cloud Load Balancer;还有自主搭建的纯软件解决方案,比如 HAProxy, NGINX 和 Envoy. 中间代理的解决方案的好处是用户使用简单。用户只要通过 DNS 连接 Load Balancer 即可,其他不用关心。缺点就是这种方案的 Load Balancer (即使是一个集群)其实是一个故障单点而且也是规模的瓶颈。一个中间代理通常也是一个黑盒,运维起来困难。观察到的问题有可能出在 Client?也有可能是物理网络?或者中间代理?或者后端?很难确定。
边缘代理 Edge proxy
Figure 5: Edge proxy load balancing topology边缘代理的拓扑其实上是中间代理模式的一个变种,区别是前者的 Client 访问 Load Balancer 是通过公网。在这种场景下,Load Balancer 通常必须提供额外的gateway 特性,比如 TLS 中断,限速,认证和复杂的流量路由。它的优点和缺点跟中间代理模式的一样。通常不可避免的要为一个面向公网的大型分布式系统专门部署一个 Edge proxy。Client 通常是通过 DNS 访问系统,这对于服务的 owner 来说是不可控的。而且,出于安全考虑,必须有一个单一的 gateway 来让所有的公网流量进入系统。
嵌入 Client 的库 Embedded client library
Figure 6: Load balancing via embedded client library为了避免 Middle Proxy 模式的单点故障问题,一些比较复杂的解决方案将 Load Balancer 以库的形式嵌入到服务中,如图6所示。在支持的功能上面,库与库之间的差别很大。在这个分类里面,功能丰富,比较知名的有 Finagle,Eureka/Ribbon/Hystrix,gRPC(主要是调用 Google 内部的 Stubby 系统)。基于库的解决方案主要的优势在于完全将 Load Balancer 的所有功能分布到每一个 Client 中,解决了之前说的单点和扩容的问题。但是这种方案的最大缺点就是需要针对每种使用到的开发语言都要实现一个库,而用不同的语言实现一个非常复杂的网络库,这个成本还是很高的。另外,还要考虑到库的升级,对于一个大型的服务架构来说,要升级一个库也是非常痛苦的,这通常会导致多个版本的库存在,这样维护起来会非常麻烦。但是只要克服多语言开发和升级的问题,这种方案也是非常成功的。
跨斗代理 Sidecar proxy
Figure 7: Load balancing via sidecar proxySidecar proxy 是 Embedded client library 方案的一个变种,如图 7 所示。最近几年这种拓扑方案以 『service mesh』的名字流行起来。Sidecar proxy 的思想就是通过另外一个不同进程来进行网络访问,这样虽然牺牲一点性能,但是却可以解决 Embedded client library 多语言实现的问题。截至撰写本文时,最流行的 sidecar proxy 模式的负载均衡器有 Envoy,Nginx,HAProxy,Linkerd。有关 sidecar proxy 方法更详细的描述请看我的这篇介绍 Envoy 的文章和 service mesh 数据面板和控制面板的对比文章。
不同拓扑类型的优势/劣势总结
Middle proxy 是最容易使用的一种方案,但是它有单点故障,扩容限制和黑盒操作的问题Edge proxy 和 middle proxy 类似Embedded library proxy 提供了最好的性能和扩容能力,但是有多语言实现和升级的问题Sidecar proxy 的性能虽然没有 embedded library proxy 的好,但是也没有它的限制总之,我认为对于服务之间的通信,sidecar proxy (service mesh)会逐渐取代其他的模式。进入 service mesh 的流量需要先通过 edge proxy.
当前 L4 负载均衡的当前水平
现在 L4 负载均衡还有意义吗?我们之前的讲了 L7 的负载均衡对现代的协议多么多么好,接下来我们也会详细说一下,那 L4 的负载均衡就没有意义了吗?绝对不是!
虽然我认为在服务之间的通信,L7 负载均衡最终会替代 L4 的负载均衡,但是 L4 在边缘模式上还有很重要的意义,当今大型的分布式系统架构通常使用 L4/L7 两层负载均衡,服务之间使用 L7 负载均衡,在 L7 负载均衡前部署 L4 负载,这样的好处有:
因为 L7 负载均衡需要执行更多的分析,转换和路由应用层流量,它能处理的流量相对于优化后的 L4 负载均衡还是小一些的。这就决定了 L4 更适合处理特定类型的 DoS 攻击(比如,SYN floods,generic packet flood attacks等)L7 负载均衡器通常开发和部署比较活跃,也就更容易产生 Bug。有一个 L4 的负载均衡在 L7 的负载均衡前面可以做健康检查,draining L7 的流量,方便 L7 的部署和升级,这要比 L4 的负载均衡部署容易,L4 通常使用 BGP和ECMP的方式(下面会细说)。总之呢,L7 的负载均衡之所以 Bug 多正是因为它功能的复杂性,L4 的的负载均衡在 L7 前面可以让流量绕过一些错误和异常,这样系统总体的稳定性提高了以下我们将讨论 middle/edge proxy 模式下 L4 负载均衡的不同设计,这些设计通常不适用于 embedded client library 和 sidecar proxy 模式。
TCP/UDP termination load balancers
Figure 8: L4 termination load balancer第一类 L4 负载均衡器就是仍然还在使用的中断式的负载均衡器,如图 8 所示。这个是与上文 L4 负载均衡器简介中介绍的那种是一样的。这种负载均衡器使用两个独立的连接:一个是 Client 和负载均衡器之间的连接,一个是负载均衡器与后端的连接。这种负载均衡器还在使用的原因有:
相对容易实现在靠近 Client 一端中断连接有很大的性能优势。具体地看,如果一个中断负载均衡器能放置的离 Client 更近,而 Client 使用的是弱网(蜂窝网络),这种情况下,在数据进入可靠的光纤传输转发到最终目的地之前,重传可以更快。换句话说,这种类型的负载均衡器可以在用于原始TCP连接中断的 PoP 场景中。TCP/UDP passthrough load balancers
Figure 9: L4 passthrough load balancer
第二种类型的 L4 负载均衡器是透传型的,如图 9 所示。这种类型负载均衡器不会中断 TCP 连接,而是在经过链接跟踪(Connection tracking)和网络地址置换(NAT)之后,直接将每一条链接的包转发给一个选定的后端。我们首先来看一下什么是链接跟踪和网络地址转换:
Connection tracking: 是指 Load Balancer 持续跟踪每一条活跃的 TCP 连接状态的过程。这一过程包含的数据有握手是否完成,是否收到 FIN,链接的空闲时长,每条链接对应了哪一个后端等等NAT: 是指在数据包经过 Load balancer 时,Load balancer 利用 connection tracking 的数据来修改数据包的 IP/PORT 信息的过程通过使用 Connection tracking 和 NAT,Load balancer 可以把书大部分的原生 TCP 流量从 Client 透传到后端。举例,假如 Client 要和 1.2.3.4:80 通信,而选中的后端地址是 10.0.0.2:9000. Client 的 TCP 包先会到达 Load balancer 1.2.3.4:80,然后 Load balancer 修改目的 IP 和端口为 10.0.0.2:9000,同时也会把源 IP 修改为 Load balancer 自己的 IP。这样当后端响应TCP包时,也会先经过 Load balancer,再经过 Connection tracking 和 NAT 之后,包又透传给了 Client。
为什么它相对于中断的load balancer 复杂反而可以用来取代中断的 load balancer?
几个理由:
性能和资源利用由于透传的 load balancer 不会中断 TCP 连接,所以它们不需要缓存任何 TCP 窗口,而保存每条连接的状态需要的存储是非常小的,使用一个高效的哈希表就可以满足需求了。因此,透传 load balancer 通常比中断的 load balancer 可以处理更大量的连接和流量。
允许后端执行自定义的拥塞控制TCP 拥塞控制可以控制互联网终端之间发送数据的量,避免耗尽可用带宽和缓冲。因为透传 load balancer 是不会中断 tcp 连接,所以它不参与拥塞控制。这意味着可以允许后端使用不同的拥塞控制算法。可以更容易的实验拥塞控制变化。(最近刚出的 BBR)
是 DSR load balancer 和 L4 负载均衡的集群化的基础透传负载均衡需要更高级的 L4 负载均衡技术,比如 DSR 和支持分布式一致性哈希的集群化方案
Direct server return (DSR)
Figure 10: L4 Direct server return (DSR)DSR load balancer 如图 10 所示。DSR 建立在前文提到的透传 load balancer 之上。 DSR 是一种优化:只有入口/请求流量经过 load balancer。出口和响应流量绕过 load balancer 直接回到 client。使用 DSR 最主要的原因是在大部分的负载情况下,响应的流量远远大于请求的流量(比如,HTTP 请求/响应模式)。假如 10% 流量是请求的,90% 的流量是响应的,如果一个 load balancer 使用 DSR 方案,那么它只需要 1/10 的能力就可以满足系统需求了。因为以往 load balancer 相当的昂贵,这样的优化对于系统成本和可靠性(少即是好)有非常大的意义。DSR load balancer 可以扩展透传 load balancer 的概念:
Load balancer 仍然可以执行半连接跟踪。因为响应包不过经过 load balancer,所以 load balancer 不会意识到完整的 TCP 连接状态。但是,load balancer 可以通过查看来自 client 的包来推断出连接的状态,这样就可以使用各种类的空间时间超时。Load balancer 不再使用 NAT,而是通常使用 Generic Routing Encapsulation(GRE) 封装从 load balancer 发往后端的 IP 包。这样,当后端收到封装的包以后,解包后可以知道 client 原始的 IP 和 Port。这样,允许后端直接响应 client 而不需要响应的包经常 load balancer.DSR load balancer 一个重要的部分是后端可以参与到负载均衡的过程中。后端需要更合适的配置 GRE 通道,也依赖更底层的网络配置细节,可能需要自己的连接跟踪和NAT。需要注意的是在透传 load balancer 和 DSR load balancer 的设计中,可以通过 load balancer 和后端设置连接跟踪,NAT,GRE等多种方式。但是这个话题不在我们这篇文章的讨论范围内。
Fault tolerance via high availability pairs 通过高可用性对来容错
Figure 11: L4 fault tolerance via HA pairs and connection tracking到目前为止, 我们一直在独立的讨论 load balancer 的设计。透传和DSR load balancer 都需要一定量的连接跟踪和 load balancer 自己的状态。那如果 load balancer 挂了呢?如果一个单一的 load balancer 实例挂掉了,所有经过这个 load balancer 的连接都会断开。取决于应用的类型,但是通常这样会对应用的性能造成很大的影响。
以往,L4 load balancer 通常是硬件设备,可以从各大供应商购买(Cisco, Juniper,F5 等)。这些设备非常贵但是可以处理大量的流量。为了避免 load balancer 单点故障导致应用程序中断,load balancer 通常是以高可用对的方式来部署,如图 11 所示。一个经典的 HA load balancer 设置如下:
一对 HA的边缘路由器服务一定数量的虚IP(VIP)。这些边缘路由器发通过 BGP 协议发布 VIP。主边缘路由器的 BGP 权重高于备用的,这样,才正常状态下,主边缘路由器服务所有流量。(BGP 是一个非常复杂的协议;考虑这篇文章的目的,我们可以仅认为 BGP 是一个机制:网络设备可以通过 BGP 让其他的网络设备知道自己当前可以接受流量。)同样地,主 L4 load balancer 也通过 BGP 协议通知边缘路由器,而且也有一个相对于备份 load balancer 更高的 BGP 权重,所以,正常状态下,主 load balancer 处理所有的流量主 load balancer 与所有的后端建立连接,而且与备份 load balancer 共享连接跟踪状态。这样,如果主的挂掉,备用的可以接管所有活跃的连接。这两个边缘路由器和两个 load balancer 都是交叠连接,这意味着如果一个边缘的路由器或者一个 Load balancer 挂掉,或者是 BGP 发布取消,备份的可以马上接管流量。以上的配置很多高流量的互联网应用仍然在使用,但是,这种方式也有很多缺点:
VIP 必须根据能力被正确的分布到不同的 HA load balancer 对上。如果一个单一的 VIP 增长超过了一个 HA 对的能力,那 VIP 需要被拆分成多个 VIP资源利用率比较低。在正常状态上,50% 的资源是空闲的。考虑到以往的 load balancer 都是硬件,这相当于一个大的资本浪费。现代的分布式系统设计倾向于支持更强的容错性,比如,最好可以支持多个设备同时故障但是系统仍然正常。一个 HA load balancer 对如果主备全挂掉的时候会完全失效私有的硬件设备贵而且还依赖于供应商。大家通常希望使用在通常的商业服务器上部署可以水平扩展的软件方案来替换这些硬件设备Fault tolerance and scaling via clusters with distributed consistent hashing
通过支持分布式一致性哈希的集群实现容错和扩容
Figure 12: L4 fault tolerance and scaling via clustered load balancers and consistent hashing
最早从 2000 年中期开始,大型的互联网基础设施开始设计和部署新的大量并行 L4 负载均衡系统,如图 12 所示。这个系统的目标是:
避免前文提到的 HA 对方案的缺陷脱离对硬件 load balancer 的依赖工作原理如下:
N 个边缘路由器以同样的 BGP 权重向外发布所有的 Anycast VIP。通常使用 ECMP 路由来保证来自同一条流的数据包都能达到同一个边缘路由器。一个流通过用一个 4 元组来表示<source ip, source port, dest ip, dest port>.(简单来说,ECMP就是一种使用一致性哈希把数据包分发到一批具有相同权重的网络链接上)。虽然边缘路由器不是特别关心数据包到哪里去,但是通常优先保证来自同一条流的数据包使用相同的链接集合以避免包乱序影响性能。N 个 L4 load balancer 机器以同样的 BGP 权重向边缘路由器发布一组VIP,同样使用 ECMP,边缘路由器为同一条流选择相同的 load balancer.每一个 L4 load balancer 机器通常执行半连接跟踪,然后使用一致性哈希算法为一条流选择一个后端。用 GRE 封装从 load balancer 发往后端的数据包。使用 DSR 将数据包直接从后端经过边缘路由器发向 clientL4 load balancer 使用一致性哈希算法是一个非常热门的研究。主要是围绕着均衡负载,最小化延迟,最小化后端变化期间的服务中断和最小化内存开销进行权衡取舍。关于这个话题的完整讨论也超出了本文的范畴。让我们看一下以上的设计如何消除了高可用对的所有缺陷:
新的边缘路由器和负载均衡器机器可以按需添加。每一层都使用了一致性哈希尽量减少了节点增减对流量的影响资源的使用可以按需运行,同时保证足够的突发容限和容错边缘路由器和负载均衡器都现在都可以使用商业硬件构建,而成本只是传统硬件负载均衡器的一小部分(更多见下文)关于这个设计,经常被问到的问题是『为什么不让边缘路由器直接和后端通信?为什么我们还需要负载均衡器?』主要原因是考虑到DoS 缓解和后端操作的简便性。如果没有负载均衡器,每一个后端不得不参与到 BGP 中而且执行滚动部署的时候更困难。
所有的现代 L4 负载均衡器都在朝着这种设计(或者某种变化 )方向演进。最著名的两个例子是 Google 的 Maglev 和 Amazon 的NLB。目前没有任何开源负载均衡器实现了这种设计,但是,据我了解,有一家公司正在计划在2018年发布一个开源的此种负载均衡器。我非常期望这个发布,因为现代的 L4 的负载均衡器是网络领域的开源软件中一个关键缺失。
L7 负载均衡的当前水平
是的,确实是这样的。最近几年,L7 负载均衡器/代理的发展开始出现了复苏。这契合了分布式系统中对微服务架构的推进。从根本上说,固有故障的网络更难高效运维,尤其是当其被越来越多使用时。而且,自动扩容,容器调度等技术的出现意味着在静态文件中配置静态 IP 的日子已经不复存在。系统不仅更多的使用网络,而且越来越动态,需要负载均衡器有新的功能。在这个章节,我会简要的总结一下在现代 L7 负载均衡器中发展最快的领域。
协议支持
现代 L7 负载均衡器已经显式增加了对很多协议的支持。负载均衡器对应用的流量知道的越多,就可以在观测数据的输出,高级的负载均衡和路由等方面做更多复杂的事情。比如,Envoy 已经针对 HTTP/1,HTTP2,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 负载均衡器的 HA 对在技术上是可行的,但是这是一项重大任务。
总之,不管是 L4 还是 L7 负载均衡领域,业界都是在从 HA 对向通过一致性哈希实现水平扩容的系统转移。
其他
L7 负载均衡器正在以惊人的节奏演化。比如,了解一下 Envoy 提供的负载均衡技术,可以看一下 Envoy 的总体架构。
全局负载均衡和中心化的控制面板
Figure 13: Global load balancing负载均衡的特性将会渐渐的把单个的负载均衡器作为一个常用设备。我认为,真正的创新和商业机会会集中在控制面板上。图 13 展示了一个 全局负载均衡系统 的示例。在这个例子中,一些事情发生了变化:
每一个 sidecar proxy 与三个不同 zone 的后端通信如图所示,90% 的流量转发到了 zone C,5% 的流量分别转发给了 zone A 和 B所有的 sidecar proxy 和后端定期上报状态到全局负载均衡器。这样全局负载均衡器可以根据延迟,消耗,负载,故障等信息进行综合决策全局负载均衡器周期性的发送当前的路由信息配置到每一个 sidecar proxy全局负载均衡器将逐渐的承担更复杂的事情,而这些事情是任何一个负载均衡的个体无法完成的。比如:
自动检测和绕过故障的 zone应用全局安全和路由策略通过使用机器学习和神经网络检测和消除异常流量,包括 DDoS 攻击提供集中化的 UI 和可视化,让所有的工程师都可以理解和操作整个分布式系统为了实例全局负载均衡,用于数据平面的负载均衡器必须具有复杂的动态配置的能力。更多信息,请看我的博客 Envoy’s universal data plane API 和 service mesh data plane vs. control plane。
从硬件到软件的演进
目前为止,这篇文章只是在讲 L4 负载均衡器高可用对的时候简单提到了硬件和软件。那在这个领域的业务趋势是什么呢?
这条推特确实有点搞笑夸张了,但是确实对当前的趋势做了总结:
以往,路由器和负载均衡器确实是非常昂贵的硬件逐渐地,大部分 L3/L4 的网络设备正在被商业服务器硬件,商业网卡和基于框架(如IPVS,DPDK和fd.io)等构建的专门的软件解决方案所替代。一个成本低于5000刀的现代数据中心的机器使用 Linux 和基于 DPDK 开发的用户态应用轻松地使用非常小的数据包使 80Gbps 的网卡饱和。同时,廉价和基本的路由器和交换机 ASIC 被包装成商业路由器,而它们能以惊人的带宽和包速率进行ECMP路由。复杂的 L7 负载均衡器软件,比如 NGINX,HAProxy 和 Envoy 正在快事迭代和蚕食这个领域的供应商(比如F5)的市场。因此,L7的负载均衡器也正在逐渐向商业的软件解决方案演进。同时,大的云服务提供商正推动整个行业向向IaaS,CaaS,FaaS方向演进。这意味着越来越少的工程师需要了解物理网络的工作原理(上文提到的『黑魔法』和『一些我们不再需要知道的事情』)总结和未来的负载均衡
总而言之,本文的关键要点是:
负载均衡器在现代分布式系统中是一个关键组件负载均衡器有两个主要的分类:L4 和 L7L4 和 L7 负载均衡器都与现代架构有关L4 负载均衡器正在向可以水平扩容的分布式一致性哈希的解决方案演进由于最近动态微服务架构的激增,L7 负载均衡器最近被投入很大全局负载均衡及控制面板和数据面板的分离是负载均衡的未来,也是未来创业和商业机会的所在行业正在积极转向用于网络解决方案的开源硬件和软件。我相信传统的负载均衡提供商,如F5,将很快会被开源软件和云供应商所取代。传统的路由器和交换机供应商,如 Arista/Cumulus 等,我认为他们在预置部署的道路上还有很大的跑道,但是最终也将会被公共云供应商和他们自己开发的物理网络所取代。总之,我认为这是一个对于计算机网络最好的时代!大多数系统向开源和软件的转变正在将迭代速度提高几个数量级。此外,随着分布式系统通过『serverless』范例继续向动态化迈进,底层网络和负载均衡系统的复杂性将会相应的增加。