learn-tech/专栏/周志明的架构课/20_常见的四层负载均衡的工作模式是怎样的?.md
2024-10-16 06:37:41 +08:00

25 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        20 _ 常见的四层负载均衡的工作模式是怎样的?
                        你好,我是周志明。

在上节课我们学习了利用CDN来加速网络性能的工作内容包括路由解析、内容分发、负载均衡和它所支持的应用。其中负载均衡是相对独立的内容它不仅在CDN方面有应用在大量软件系统的生产部署中也都离不开负载均衡器的支持。所以今天这节课我们就一起来了解下负载均衡器的作用与原理。

在互联网时代的早期,网站流量还比较小,业务也比较简单,使用单台服务器基本就可以满足访问的需要了。但时至今日,互联网也好,企业级也好,一般实际用于生产的系统,几乎都离不开集群部署了。

一方面,不管是采用单体架构多副本部署还是微服务架构,也不管是为了实现高可用还是为了获得高性能,信息系统都需要利用多台机器来扩展服务能力,希望用户的请求不管连接到哪台机器上,都能得到相同的处理。

另一方面,如何构建和调度服务集群这件事情,又必须对用户一侧保持足够的透明,即使请求背后是由一千台、一万台机器来共同响应的,这也都不是用户会关心的事情,用户需要记住的只有一个域名地址而已。

那么这里承担了调度后方的多台机器以统一的接口对外提供服务的技术组件就是“负载均衡器”Load Balancer了。

真正的大型系统的负载均衡过程往往是多级的。比如在各地建有多个机房或者是机房有不同网络链路入口的大型互联网站然后它们会从DNS解析开始通过“域名” → “CNAME” → “负载调度服务” → “就近的数据中心入口”的路径先根据IP地址或者其他条件将来访地用户分配到一个合适的数据中心当中然后才到了我们马上要讨论的各式负载均衡。

这里我先跟你说明一下在DNS层面的负载均衡的工作模式与我在前几讲中介绍的DNS智能线路、内容分发网络等的工作原理是类似的它们之间的差别只是数据中心能提供的不仅是缓存而是全方位的服务能力。所以这种负载均衡的工作模式我就不再重复介绍了后面我们主要聚焦在讨论网络请求进入数据中心入口之后的其他级次的负载均衡。

好,那么接下来,我们就先从负载均衡的实现形式开始了解吧。

负载均衡的两种形式

实际上,无论我们在网关内部建立了多少级的负载均衡,从形式上来说都可以分为两种:四层负载均衡和七层负载均衡。

那么,在详细介绍它们是什么、如何工作之前,我们先来建立两个总体的、概念性的印象:

四层负载均衡的优势是性能高,七层负载均衡的优势是功能强。 做多级混合负载均衡,通常应该是低层的负载均衡在前,高层的负载均衡在后(你可以先想一想为什么?)。

这里我们所说的“四层”“七层”一般指的是经典的OSI七层模型中第四层传输层和第七层应用层。你可以参考下面表格中给出的维基百科上对OSI七层模型的介绍我们在后面还会多次使用它。

另外我还想说明一点就是现在人们所说的“四层负载均衡”其实是多种均衡器工作模式的统称。“四层”的意思是说这些工作模式的共同特点是都维持着同一个TCP连接而不是说它就只工作在第四层。

事实上这些模式主要都是工作在二层数据链路层可以改写MAC地址和三层上网络层可以改写IP地址单纯只处理第四层传输层可以改写TCP、UDP等协议的内容和端口的数据无法做到负载均衡的转发因为OSI的下面三层是媒体层Media Layers上面四层是主机层Host Layers。所以既然流量都已经到达目标主机上了也就谈不上什么流量转发最多只能做代理了。

但出于习惯和方便,现在几乎所有的资料都把它们统称为四层负载均衡,这里我也就遵循习惯,同样称呼它为四层负载均衡。而如果你在某些资料上,看见“二层负载均衡”“三层负载均衡”的表述,这就真的是在描述它们工作的层次了,和我这里讲的“四层负载均衡”并不是同一类意思。

常见的四层负载均衡的工作模式

好,回到我们这一讲的重点上来,我们一起来看看几种常见的四层负载均衡的工作模式都是怎样的。

数据链路层负载均衡

这里你可以参考前面的OSI模型表格数据链路层传输的内容是数据帧Frame比如我们常见的以太网帧、ADSL宽带的PPP帧等。当然了在我们所讨论的具体上下文里探究的目标必定就是以太网帧了。按照IEEE 802.3标准最典型的1500 Bytes MTU的以太网帧结构如下表所示

阅读链接补充:- 802.1Q 标签- 以太类型- 冗余校验- 帧间距

在这个帧结构中其他数据项的含义你可以暂时不去理会只需要注意到“MAC目标地址”和“MAC源地址”两项即可。

我们知道每一块网卡都有独立的MAC地址而以太帧上的这两个地址告诉了交换机此帧应该是从连接在交换机上的哪个端口的网卡发出送至哪块网卡的。

数据链路层负载均衡所做的工作是修改请求的数据帧中的MAC目标地址让用户原本是发送给负载均衡器的请求的数据帧被二层交换机根据新的MAC目标地址转发到服务器集群中对应的服务器后面都叫做“真实服务器”Real Server的网卡上这样真实服务器就获得了一个原本目标并不是发送给它的数据帧。

由于二层负载均衡器在转发请求过程中只修改了帧的MAC目标地址不涉及更上层协议没有修改Payload的数据所以在更上层第三层看来所有数据都是没有被改变过的。

这是因为第三层的数据包也就是IP数据包中包含了源客户端和目标均衡器的IP地址只有真实服务器保证自己的IP地址与数据包中的目标IP地址一致这个数据包才能被正确处理。

所以我们在使用这种负载均衡模式的时候需要把真实物理服务器集群所有机器的虚拟IP地址Virtual IP AddressVIP配置成跟负载均衡器的虚拟IP一样这样经均衡器转发后的数据包就能在真实服务器中顺利地使用。

另外也正是因为实际处理请求的真实物理服务器IP和数据请求中的目的IP是一致的所以响应结果就不再需要通过负载均衡服务器进行地址交换我们可以把响应结果的数据包直接从真实服务器返回给用户的客户端避免负载均衡器网卡带宽成为瓶颈所以数据链路层的负载均衡效率是相当高的。

整个请求到响应的过程如下图所示:

那么这里你就可以发现数据链路层负载均衡的工作模式是只有请求会经过负载均衡器而服务的响应不需要从负载均衡器原路返回整个请求、转发、响应的链路形成了一个“三角关系”。所以这种负载均衡模式也被很形象地称为“三角传输模式”Direct Server ReturnDSR也有人叫它是“单臂模式”Single Legged Mode或者“直接路由”Direct Routing

不过,虽然数据链路层负载均衡的效率很高,但它并不适用于所有的场合。除了那些需要感知应用层协议信息的负载均衡场景它无法胜任外(所有的四层负载均衡器都无法胜任,这个我后面介绍七层负载均衡器时会一并解释),在网络一侧受到的约束也很大。

原因是二层负载均衡器直接改写目标MAC地址的工作原理决定了它与真实服务器的通讯必须是二层可达的。通俗地说就是它们必须位于同一个子网当中无法跨VLAN。

所以,这个优势(效率高)和劣势(不能跨子网)就共同决定了,数据链路层负载均衡最适合用来做数据中心的第一级均衡设备,用来连接其他的下级负载均衡器。

好,我们再来看看第二种常见的四层负载均衡工作模式:网络层负载均衡。

网络层负载均衡

根据OSI七层模型我们可以知道在第三层网络层传输的单位是分组数据包Packets这是一种在分组交换网络Packet Switching NetworkPSN中传输的结构化数据单位。

我拿IP协议来给你举个例子吧。一个IP数据包由Headers和Payload两部分组成Headers长度最大为60 Bytes它是由20 Bytes的固定数据和最长不超过40 Bytes的可选数据组成的。按照IPv4标准一个典型的分组数据包的Headers部分的结构是这样的

同样我们也不需要过多关注表中的其他信息只要知道在IP分组数据包的Headers带有源和目标的IP地址即可。

源和目标IP地址代表了“数据是从分组交换网络中的哪台机器发送到哪台机器的”所以我们就可以沿用与二层改写MAC地址相似的思路通过改变这里面的IP地址来实现数据包的转发。

具体有两种常见的修改方式:

第一种是保持原来的数据包不变新创建一个数据包把原来数据包的Headers和Payload整体作为另一个新的数据包的Payload在这个新数据包的Headers中写入真实服务器的IP作为目标地址然后把它发送出去。

如此经过三层交换机的转发当真实服务器收到数据包后就必须在接收入口处设计一个针对性的拆包机制把由负载均衡器自动添加的那层Headers扔掉还原出原来的数据包来进行使用。

这样真实服务器就同样拿到了一个原本不是发给它目标IP不是它的数据包从而达到了流量转发的目的。

在那个时候还没有流行起“禁止套娃”的梗所以设计者给这种“套娃式”的传输起名为“IP隧道”IP Tunnel传输也是相当的形象了。

当然尽管因为要封装新的数据包IP隧道的转发模式比起直接路由的模式效率会有所下降但因为它并没有修改原有数据包中的任何信息所以IP隧道的转发模式仍然具备三角传输的特性即负载均衡器转发来的请求可以由真实服务器去直接应答无需再经过均衡器原路返回。

而且因为IP隧道工作在网络层所以可以跨越VLAN也就摆脱了我前面所讲的直接路由模式中网络侧的约束。现在我们来看看这种转发模式从请求到响应的具体过程

不过这种转发模式也有缺点就是它要求真实服务器必须得支持“IP隧道协议”IP Encapsulation也就是它得学会自己拆包扔掉一层Headers。当然这个其实并不是什么大问题现在几乎所有的Linux系统都支持IP隧道协议。

可另一个问题是这种模式仍然必须通过专门的配置必须保证所有的真实服务器与均衡器有着相同的虚拟IP地址。因为真实服务器器在回复该数据包的时候需要使用这个虚拟IP作为响应数据包的源地址这样客户端在收到这个数据包的时候才能正确解析。

这个限制就相对麻烦了一些它跟“透明”的原则冲突了需由系统管理员去专门介入。而且并不是在任何情况下我们都可以对服务器进行虚拟IP的配置的尤其是当有好几个服务共用一台物理服务器的时候。

那么在这种情况下我们就必须考虑第二种改变目标数据包的方式直接把数据包Headers中的目标地址改掉修改后原本由用户发给均衡器的数据包也会被三层交换机转发送到真实服务器的网卡上而且因为没有经过IP隧道的额外包装也就无需再拆包了。

但问题是这种模式是修改了目标IP地址才到达真实服务器的而如果真实服务器直接把应答包发回给客户端的话这个应答数据包的源IP是真实服务器的IP也就是均衡器修改以后的IP地址那么客户端就不可能认识该IP自然也就无法再正常处理这个应答了。

因此我们只能让应答流量继续回到负载均衡负载均衡把应答包的源IP改回自己的IP然后再发给客户端这样才能保证客户端与真实服务器之间正常通信。

如果你对网络知识有些了解的话肯定会觉得这种处理似曾相识这不就是在家里、公司、学校上网的时候由一台路由器带着一群内网机器上网的“网络地址转换”Network Address TranslationNAT操作吗

这种负载均衡的模式的确就被称为NAT模式。此时负载均衡器就是充当了家里、公司、学校的上网路由器的作用。

NAT模式的负载均衡器运维起来也十分简单只要机器把自己的网关地址设置为均衡器地址就不需要再进行任何额外设置了。

我们来看看这种工作模式从请求到响应的过程:

不过这里你还要知道的是在流量压力比较大的时候NAT模式的负载均衡会带来较大的性能损失比起直接路由和IP隧道模式甚至会出现数量级上的下降。

这个问题也是显而易见的因为由负载均衡器代表整个服务集群来进行应答各个服务器的响应数据都会互相争抢均衡器的出口带宽。这就好比在家里用NAT上网的话如果有人在下载你打游戏可能就会觉得卡顿是一个道理此时整个系统的瓶颈很容易就出现在负载均衡器上。

不过还有一种更加彻底的NAT模式就是均衡器在转发时不仅修改目标IP地址连源IP地址也一起改了这样源地址就改成了均衡器自己的IP。这种方式被叫做Source NATSNAT

这样做的好处是真实服务器连网关都不需要配置了,它能让应答流量经过正常的三层路由,回到负载均衡器上,做到了彻底的透明。

但它的缺点是由于做了SNAT真实服务器处理请求时就无法拿到客户端的IP地址了在真实服务器的视角看来所有的流量都来自于负载均衡器这样有一些需要根据目标IP进行控制的业务逻辑就无法进行了。

应用层负载均衡

前面我介绍的两种四层负载均衡的工作模式都属于“转发”即直接将承载着TCP报文的底层数据格式IP数据包或以太网帧转发到真实服务器上此时客户端到响应请求的真实服务器维持着同一条TCP通道。

但工作在四层之后的负载均衡模式就无法再进行转发了只能进行代理。此时正式服务器、负载均衡器、客户端三者之间是由两条独立的TCP通道来维持通讯的。

那么,转发与代理之间的具体区别是怎样的呢?我们来看一个图例:

首先,“代理”这个词,根据“哪一方能感知到”的原则,可以分为“正向代理”“反向代理”和“透明代理”三类。

正向代理就是我们通常简称的代理,意思就是在客户端设置的、代表客户端与服务器通讯的代理服务。它是客户端可知,而对服务器是透明的。 反向代理是指设置在服务器这一侧,代表真实服务器来与客户端通讯的代理服务。此时它对客户端来说是透明的。 透明代理是指对双方都透明的,配置在网络中间设备上的代理服务。比如,架设在路由器上的透明翻墙代理。

那么根据这个定义很显然七层负载均衡器就属于反向代理中的一种如果只论网络性能七层负载均衡器肯定是无论如何比不过四层负载均衡器的。毕竟它比四层负载均衡器至少要多一轮TCP握手还有着跟NAT转发模式一样的带宽问题而且通常要耗费更多的CPU因为可用的解析规则远比四层丰富。

所以说,如果你要用七层负载均衡器去做下载站、视频站这种流量应用,一定是不合适的,起码它不能作为第一级均衡器。

但是,如果网站的性能瓶颈并不在于网络性能,而是要论整个服务集群对外所体现出来的服务性能,七层负载均衡器就有它的用武之地了。这里,七层负载均衡器的底气就来源于,它是工作在应用层的,可以感知应用层通讯的具体内容,往往能够做出更明智的决策,玩出更多的花样来。

我举个生活中的例子。

四层负载均衡器就像是银行的自助排号机,转发效率高且不知疲倦,每一个达到银行的客户都可以根据排号机的顺序,选择对应的窗口接受服务;而七层负载均衡器就像银行的大堂经理,他会先确认客户需要办理的业务,再安排排号。这样,办理理财、存取款等业务的客户,可以根据银行内部资源得到统一的协调处理,加快客户业务办理流程;而有些无需柜台办理的业务,由大堂经理直接就可以解决了。

比如说,反向代理的工作模式就能够实现静态资源缓存,对于静态资源的请求就可以在反向代理上直接返回,无需转发到真实服务器。

这里关于代理的工作模式,相信你应该是比较熟悉的,所以这里关于七层负载均衡器的具体工作过程我就不详细展开了。下面我来列举一些七层代理可以实现的功能,让你能对它“功能强大”有个直观的感受:

在上一讲我介绍CDN应用的时候就提到过所有CDN可以做的缓存方面的工作就是除去CDN根据物理位置就近返回这种优化链路的工作外七层负载均衡器全都可以实现比如静态资源缓存、协议升级、安全防护、访问控制等等。 七层负载均衡器可以实现更智能化的路由。比如根据Session路由以实现亲和性的集群根据URL路由实现专职化服务此时就相当于网关的职责甚至根据用户身份路由实现对部分用户的特殊服务如某些站点的贵宾服务器等等。 某些安全攻击可以由七层负载均衡器来抵御。比如一种常见的DDoS手段是SYN Flood攻击即攻击者控制众多客户端使用虚假IP地址对同一目标大量发送SYN报文。从技术原理上看因为四层负载均衡器无法感知上层协议的内容这些SYN攻击都会被转发到后端的真实服务器上而在七层负载均衡器下这些SYN攻击自然就会在负载均衡设备上被过滤掉不会影响到后面服务器的正常运行。类似地我们也可以在七层负载均衡器上设定多种策略比如过滤特定报文以防御如SQL注入等应用层面的特定攻击手段。 很多微服务架构的系统中链路治理措施都需要在七层中进行比如服务降级、熔断、异常注入等等。我举个例子一台服务器只有出现物理层面或者系统层面的故障导致无法应答TCP请求才能被四层负载均衡器感知到进而剔除出服务集群而如果一台服务器能够应答只是一直在报500错那四层负载均衡器对此是完全无能为力的只能由七层负载均衡器来解决。

均衡策略与实现

好,现在你应该也能知道,负载均衡的两大职责是“选择谁来处理用户请求”和“将用户请求转发过去”。那么到这里为止,我们只介绍了后者,即请求的转发或代理过程。

而“选择谁来处理用户请求”是指均衡器所采取的均衡策略,这一块因为涉及的均衡算法太多,我就不一一展开介绍了。所以接下来,我想从功能和应用的角度,来给你介绍一些常见的均衡策略,你可以在自己的实践当中根据实际需求去配置选择。

轮循均衡Round Robin

即每一次来自网络的请求会轮流分配给内部中的服务器从1到N然后重新开始。这种均衡算法适用于服务器组中的所有服务器都有相同的软硬件配置并且平均服务请求相对均衡的情况。

权重轮循均衡Weighted Round Robin

即根据服务器的不同处理能力给每个服务器分配不同的权值使其能够接受相应权值数的服务请求。比如服务器A的权值被设计成1B的权值是3C的权值是6则服务器A、B、C将分别接收到10%、30、60的服务请求。这种均衡算法能确保高性能的服务器得到更多的使用率避免低性能的服务器负载过重。

随机均衡Random

即把来自客户端的请求随机分配给内部中的多个服务器。这种均衡算法在数据足够大的场景下,能达到相对均衡的分布。

权重随机均衡Weighted Random

这种均衡算法类似于权重轮循算法,不过在处理请求分担的时候,它是个随机选择的过程。

一致性哈希均衡Consistency Hash

即根据请求中的某些数据可以是MAC、IP地址也可以是更上层协议中的某些参数信息作为特征值来计算需要落在哪些节点上算法一般会保证同一个特征值每次都一定落在相同的服务器上。这里一致性的意思就是保证当服务集群的某个真实服务器出现故障的时候只影响该服务器的哈希而不会导致整个服务集群的哈希键值重新分布。

响应速度均衡Response Time

即负载均衡设备对内部各服务器发出一个探测请求如Ping然后根据内部中各服务器对探测请求的最快响应时间来决定哪一台服务器来响应客户端的服务请求。这种均衡算法能比较好地反映服务器的当前运行状态但要注意这里的最快响应时间仅仅指的是负载均衡设备与服务器间的最快响应时间而不是客户端与服务器间的最快响应时间。

最少连接数均衡Least Connection

客户端的每一次请求服务在服务器停留的时间可能会有比较大的差异。那么随着工作时间加长如果采用简单的轮循或者随机均衡算法每一台服务器上的连接进程可能会产生极大的不平衡并没有达到真正的负载均衡。所以最少连接数均衡算法就会对内部中需要负载的每一台服务器都有一个数据记录也就是记录当前该服务器正在处理的连接数量当有新的服务连接请求时就把当前请求分配给连接数最少的服务器使均衡更加符合实际情况负载也能更加均衡。这种均衡算法适合长时间处理的请求服务比如FTP传输。

…………

另外,从实现角度来看,负载均衡器的实现有“软件均衡器”和“硬件均衡器”两类。

在软件均衡器方面又分为直接建设在操作系统内核的均衡器和应用程序形式的均衡器两种。前者的代表是LVSLinux Virtual Server后者的代表有Nginx、HAProxy、KeepAlived等等前者的性能会更好因为它不需要在内核空间和应用空间中来回复制数据包而后者的优势是选择广泛使用方便功能不受限于内核版本。

在硬件均衡器方面往往会直接采用应用专用集成电路Application Specific Integrated CircuitASIC来实现。因为它有专用处理芯片的支持可以避免操作系统层面的损耗从而能够达到最高的性能。这类的代表就是著名的F5和A10公司的负载均衡产品。

小结

这节课,我给你介绍了数据链路层负载均衡和网络层负载均衡的基本原理。对于一个普通的开发人员来说,可能平常不太接触这些偏向底层网络的知识,但如果你要对软件系统工作有全局的把握,进阶成为一名架构人员,那么即使不会去实际参与网络拓扑设计与运维,至少也必须理解它们的工作原理,这是系统做流量和容量规划的必要基础。

一课一思

请你思考一下:为什么负载均衡不能只在某一个网络层次中完成,而是要进行多级混合的负载均衡?另外做多级混合负载均衡,为什么应该是低层的负载均衡在前,高层的负载均衡在后?

欢迎在留言区分享你的思考和见解。如果你觉得有收获,也欢迎把今天的内容分享给更多的朋友。感谢你的阅读,我们下一讲再见。