聊聊负载均衡

235 阅读9分钟

引子

之前面试的过程中我被问道你们用的的是四层负载还是七层负载。我当时就懵了,完全不知道到这两个的负载是啥玩意,只能顾左右而言他。面试官眉头一皱,我就知道大事不好,毫无意外的挂掉了。

求知

在悔恨的心情中,我踏上了求知的道路。经过我苦心寻找,终于找到了它们的定义。

首先我们看一下负载均衡的定义:负载均衡(Load Balancing)是调度后方的多台机器,以统一的接口对外提供服务的一种技术组件。在大型的系统中,负载均衡往往是多级的。我们拿一个浏览器的请求是怎样到达服务为例来简单看一下负载均衡在里面起到的作用。 我们假设这个系统部署在不同的机房,首先会开始 DNS 解析,即 域名 -> CNAME -> 负载均衡服务 -> 就近的数据中心入口,会根据用户的 IP 路由到离用户最近的机房。真实的大型系统内部的负载均衡往往是多级的,无论在网关内部建立了多少级的负载均衡,从形式上来说都可以分为两种:四层负载均衡和七层负载均衡。我们先看一下四层负载和七层负载的特点:

  • 四层负载均衡的优势是性能高,七层负载均衡的优势是功能强。
  • 做多级混合负载均衡,通常应是低层的负载均衡在前,高层的负载均衡在后。

我们所说的 四层七层,指的是经典的 OSI 七层模型 中第四层传输层和第七层应用层,了解过计算机网络的应该都知道这个模型。需要注意的是这里的 四层负载均衡 是多种均衡器工作模式的统称,它们的共同特点是维持同一个 TCP 连接,而不是它只工作在第四层。事实上这些模式主要是工作在第二层(数据链路层,可以修改 MAC 地址)和第三层(网络层,可以修改 IP 地址)。如果到达第四层就说明他已经到达目标主机了,不能做流量转发,只能做代理了。

数据链路层的负载均衡

数据链路层负载均衡所做的工作就是修改请求的数据帧中的 MAC 目标地址,让用户原本是发送给负载均衡器的请求的数据帧,转发到服务器集群中对应的真实服务器的网卡上,这样真实服务器就获得了一个原本目标并不是发送给它的数据帧。

由于二层负载均衡器在转发请求过程中只修改了帧的 MAC 目标地址,所以在第三层看来,所有数据都是未曾被改变过的。由于 IP 数据包中包含了源(客户端)和目标(均衡器)的 IP 地址,只有真实服务器的 IP 地址与数据包中的目标 IP 地址一致,这个数据包才能被正确处理。因此使用这种负载均衡模式时,需要把真实物理服务器集群所有机器的虚拟 IP 地址(Virtual IP Address,VIP)配置成与负载均衡器的虚拟 IP 一样。因为实际处理请求的真实物理服务器 IP 和数据请求中的目的 IP 是一致的,所以响应结果就不再需要通过负载均衡服务器进行地址交换,可将响应结果的数据包直接从真实服务器返回给用户的客户端,避免负载均衡器网卡带宽成为瓶颈,因此数据链路层的负载均衡效率是相当高的。整个请求到响应的过程如下图所示:

无标题-2022-09-07-0951.png

上述只有请求经过负载均衡器,而服务的响应无须从负载均衡器原路返回的工作模式,整个请求、转发、响应的链路形成一个“三角关系”,所以这种负载均衡模式也常被很形象地称为“三角传输模式”(Direct Server Return,DSR),也有叫“单臂模式”(Single Legged Mode)或者“直接路由”(Direct Routing)。

虽然数据链路层负载均衡效率很高,但它并不能适用于所有的场合,除了那些需要感知应用层协议信息的负载均衡场景它无法胜任外,它在网络一侧受到的约束也很大。二层负载均衡器直接改写目标 MAC 地址的工作原理决定了它与真实的服务器的通信必须是二层可达的,也就是说它们必须位于同一个子网当中,无法跨 VLAN。它的优势 效率高 和劣势 不能跨子网 决定了数据链路层负载均衡最适合用来做数据中心的第一级均衡设备,用来连接其他的下级负载均衡器。

网络层的负载均衡

IP 分组数据包的报文头带有源和目标的 IP 地址。源和目标 IP 地址代表了数据是从分组交换网络中哪台机器发送到哪台机器的,我们可以根据与二层改写 MAC 地址相似的方式,通过改写 IP 地址来实现数据包的转发。具体有两种常见的修改方式。

IP Tunnel

保持原来的数据包不变,新创建一个数据包,把原来数据包当做一个报文内容即当做 Paylaod,然后在这个新数据包的 Headers 中写入真实服务器的 IP 作为目标地址,然后把它发送出去。经过三层交换机的转发,真实服务器收到数据包后,把这个自动添加的那层报文头扔掉,还原出原始数据包来进行使用。这样,真实服务器就同样拿到了一个原本不是发给它(目标 IP 不是它)的数据包,达到了流量转发的目的。这种传输方式就叫做“IP 隧道"IP Tunnel)传输。

尽管因为要封装新的数据包,IP 隧道的转发模式比起直接路由模式效率会有所下降,但由于并没有修改原有数据包中的任何信息,所以 IP 隧道的转发模式仍然具备三角传输的特性,即负载均衡器转发来的请求,可以由真实服务器去直接应答,无须再经过均衡器原路返回。而且由于 IP 隧道工作在网络层,所以可以跨越 VLAN,因此摆脱了直接路由模式中网络侧的约束。整个请求到响应的过程如下图所示: IP隧道.png 当然这种方法也有缺点,第一个缺点是它要求真实服务器必须支持“IP 隧道协议”(IP Encapsulation);另外一个缺点是这种模式必须保证所有的真实服务器与均衡器有着相同的虚拟 IP 地址,因为回复该数据包时,需要使用这个虚拟 IP 作为响应数据包的源地址,这样客户端收到这个数据包时才能正确解析。

NAT(Network Address Translation)

NAT(Network Address Translation) 模式中均衡器会把直接把数据包 Headers 中的目标地址改为真实服务器的 IP 地址,修改后均衡器再把数据包发送到真实服务器的网卡上。当真实服务器直接将应答包返回客户端时,让应答流量继续回到负载均衡,由均衡器把应答包的源 IP 改回自己的 IP,再发给客户端,这样才能保证客户端与真实服务器之间的正常通信。 整个请求到响应的过程如下图所示: NAT.png 在流量压力比较大的时候,NAT 模式的负载均衡会带来较大的性能损失,相比于其他两种方式甚至会出现数量级上的下降。这点是显而易见的,由负载均衡器代表整个服务集群来进行应答,各个服务器的响应数据都会互相争抢均衡器的出口带宽,此时整个系统的瓶颈很容易就出现在负载均衡器上。

还有一种更加彻底的 NAT 模式:即均衡器在转发时,不仅修改目标 IP 地址,连源 IP 地址也一起改了,源地址就改成均衡器自己的 IP,称作 Source NAT(SNAT)。这样做的好处是真实服务器无须配置网关就能够让应答流量经过正常的三层路由回到负载均衡器上,做到了彻底的透明。但是缺点是由于做了 SNAT,真实服务器处理请求时就无法拿到客户端的 IP 地址了,从真实服务器的视角看来,所有的流量都来自于负载均衡器,这样有一些需要根据目标 IP 进行控制的业务逻辑就无法进行。

应用层的负载均衡

但工作在四层之后的负载均衡模式就无法再进行转发了,只能进行代理,此时真实服务器、负载均衡器、客户端三者之间由两条独立的 TCP 通道来维持通信。 “代理”这个词,根据“哪一方能感知到”的原则,可以分为“正向代理”、“反向代理”和“透明代理”三类。正向代理就是我们通常简称的代理,指在客户端设置的、代表客户端与服务器通信的代理服务,它是客户端可知,而对服务器透明的。反向代理是指在设置在服务器这一侧,代表真实服务器来与客户端通信的代理服务,此时它对客户端来说是透明的。至于透明代理是指对双方都透明的,配置在网络中间设备上的代理服务,譬如,架设在路由器上的透明翻墙代理。

根据以上定义,很显然,七层负载均衡器它就属于反向代理中的一种,如果只论网络性能,七层均衡器肯定是无论如何比不过四层均衡器的,它比四层均衡器至少多一轮 TCP 握手,有着跟 NAT 转发模式一样的带宽问题,而且通常要耗费更多的 CPU,因为可用的解析规则远比四层丰富。如果网站的性能瓶颈并不在于网络性能,要论整个服务集群对外所体现出来的服务性能,七层均衡器就有它的用武之地了。它工作在应用层,可以感知应用层通信的具体内容,往往能够做出更明智的决策,玩出更多的花样来。