4.2.1 四层负载均衡工作模式
LVS(Linux Virtual Server)是软件实现的四层负载均衡系统级的解决方案。
LVS 的工作机制在于内部组件 IPVS 通过 Netfilter 的钩子机制(参见第 3 章第 3 节),完全在内核空间中处理负载均衡和转发逻辑的。根据数据包的修改方式,LVS 提供了三种不同的工作模式:直接路由(DR,Direct Routing)模式、隧道(Tunnel)模式和网络地址转换(NAT,Network Address Translation)模式。
1. DR 模式
LVS 的 DR 模式,实际上是一种链路层负载均衡技术。
链路层负载均衡的原理是,负载均衡器在接收到请求后,修改数据帧的目标 MAC 地址,将原本发给负载均衡器的数据帧重新定向,经过二层交换机转发至某个真实服务器(Real Server),使得该真实服务器接收到原本并非直接发给它的数据帧。
真实服务器的网卡接收数据帧后,因为 IP 层的目的 IP 并非本机,所以内核中的网络协议栈实际上无法处理该数据包。为了解决这个问题,需要将虚拟 IP(VIP,详细介绍将在下一节中提供)配置到本地回环接口(lo)上。这样,请求到达真实服务器后,内核的网络协议栈就能识别并正常接收该数据包。
如某个虚拟 IP(VIP)为 1.1.1.1,通过以下命令将该 IP 绑定到真实服务器的 lo 接口:
// 这里 /32 表示单个 IP 地址,也即仅将 VIP 绑定到 lo 接口,不与其他 IP 地址共享子网。
$ ip addr add 1.1.1.1/32 dev lo
为了避免真实服务器对 VIP 抢答 ARP 请求,从而导致网络问题,还必须禁用真实服务器对 VIP 的 ARP 应答。命令如下所示:
$ echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
$ echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
// 为了确保 eth0 或其他网络接口也不会响应该 VIP 的 ARP 请求,需要对每个网络接口设置相同的 ARP 参数。
$ echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
$ echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
经过上述配置后,真实服务器在本地回环接口(lo)上检测到目标 IP 为 VIP(配置的 1.1.1.1)的数据包时,将其识别为自己的地址并处理请求。处理完成后,真实服务器通过其外部接口(如 eth0)发送响应数据时,会保持原始请求中的目的 IP 地址,即 VIP(1.1.1.1),作为响应数据包的源 IP。
在 DR 模式中,请求经过负载均衡器后,真实服务器的响应无需再通过负载均衡器原路返回。整个工作模式中,请求、转发和响应形成了一个“三角关系”。因此,DR 模式形象地被称为“三角传输模式”,如图 4-7 所示。
图 4-7 DR 的三角传输模式
DR 模式的主要优势在于它特别适合于响应流量远大于请求流量的场景。如典型的 HTTP 请求/响应模式,假设请求流量仅占 10%,响应流量占 90%。通过三角传输模式,负载均衡器只需处理 1/10 的总流量,这样不仅极大节省了带宽成本,还提高了负载均衡器的可靠性(流量越低越好)。
DR 模式的缺陷也非常明显。首先,由于响应流量绕过负载均衡器,导致其无法监控完整的 TCP 连接状态,从而影响防火墙策略的应用(负载均衡器只能看到 TCP 连接的 SYN 包,而无法看到 ACK 包)。其次,由于负载均衡器与真实服务器之间是通过链路层通信,它们必须位于同一子网内,这对网络架构造成了一定的限制。
2. Tunnel 模式
数据链路层负载均衡通过改写 MAC 地址实现数据包转发。到了网络层,我们也可以采用类似修改 IP 数据包的方式重定向数据包路由。LVS 的 Tunnel 和 NAT 模式都属于网络层负载均衡,它们的主要区别在于对 IP 数据包的处理方式。
在 Tunnel 模式中,LVS 会创建一个新的 IP 数据包,并将原始 IP 数据包整体放入新数据包的负载部分(Payload)中。随后,这个新数据包通过三层交换机发送出去。当真实服务器收到数据包时,通过相应的拆包机制去除负载均衡器自动添加的额外头部,从而解析出负载部分的原始 IP 数据包,并进行正常处理。
上述的操作称之为”封包“,举一个具体例子供你参考。假设客户端(IP 203.0.113.5)向 VIP (1.1.1.1) 发送的数据包如下:
{
Source IP: 203.0.113.5,
Destination IP: 1.1.1.1,
Payload: "Request data"
}
负载均衡器接收到数据包后,选择一台真实服务器(172.12.1.3)并对其进行封装处理。
{
Source IP: 172.12.1.2,
Destination IP: 172.12.1.3,
Payload: {
Original Source IP: 203.0.113.5,
Original Destination IP: 1.1.1.1,
Original Data: "Request data"
}
}
上述将一个 IP 数据包封装在另一个 IP 数据包内,并配合相应的解包机制,正是典型的 IP 隧道技术。Linux 中的 IPIP 隧道字面意思是“IP in IP”。由于 IP 隧道在网络层工作,避免了直接路由模式的网络限制,因此 LVS Tunnel(隧道)模式可以跨越子网。
由于源数据包的所有信息均未被修改,IP 隧道模式依然保留了三角传输模式的特征(当然,仍需处理 lo 回环地址)。Tunnel 模式的请求到响应的整个过程如图 4-9 所示。
图 4-9 Tunnel 模式
Tunnel 模式相当于 DR 模式的升级(支持了跨网)。不过由于使用隧道模式,真实服务器必须支持特定的隧道技术(如 IPIP、GRE)。其次,只要是三角模式(LVS 的 DR 模式或者 Tunnel 模式)必须保证真实服务器的 lo 接口与负载均衡服务器有相同的虚拟 IP 地址。这是因为回复客户端的数据包,必须使用 VIP 作为数据包的源地址,这样客户端收到之后才能正常处理。
3. NAT 模式
另一种对 IP 数据包的修改方式是更改其头部中的目标地址,将其替换为真实服务器的地址。IP 数据包的目的地址修改后,将被三层交换机转发到真实服务器的网络接口上。
这段解释可能不够直观,但相信大多数读者都曾操作过类似的配置。例如,在家中设置路由器时,你希望外部设备可以访问家中某台运行服务器的电脑。假设家中的电脑 IP 是 192.168.1.100,并在端口 8080 上运行一个 Web 服务。你可以在路由器中设置端口转发(NAT),将外部访问路由器的 80 端口的请求转发到该电脑的 192.168.1.100:8080。这样,当外部设备通过路由器的公共 IP 访问 80 端口时,实际上就会连接到局域网内的服务器。
四层负载均衡器对 IP 数据包的改写与路由器中的“端口转发”原理相同。因此,这种负载均衡方式被称为 NAT 模式,其请求和响应的流程如图 4-10 所示。
图 4-10 NAT 模式负载均衡
举例一个具体的例子。假设客户端(203.0.113.5:37118)请求负载均衡器(1.1.1.1:80),四层负载均衡器根据调度算法挑选了某个后端服务器(10.0.0.2:8080)处理请求。
此时,四层负载均衡器处理请求和响应的逻辑如下:
- 当客户端请求到达负载均衡器时,负载均衡器执行 NAT 操作:
- 首先是 DNAT(目标地址转换) 操作:将目标 IP 和端口(1.1.1.1:80)改为后端服务器的 IP 和端口(10.0.0.2:8080),这使得请求能够被路由至指定的后端服务器处理。
- 为了保持通信的完整性,负载均衡器还会执行 SNAT(源地址转换)操作。也就是原始源 IP 和端口(203.0.113.5:37118)改为四层负载均衡器的 IP 和端口(1.1.1.1:某个随机端口)。SNAT 操作确保后端服务器认为请求是来自负载均衡器,而不是直接来自客户端。
- 当后端服务器返回响应时,负载均衡器执行相反的 NAT 操作:
- 将源 IP 和端口改回 1.1.1.1:80
- 将目标 IP 和端口改回客户端的 203.0.113.5:37118
最终,客户端请求/接收的都是负载均衡器的 IP 和端口,并不知道实际的后端服务器信息。
从上述可见,NAT 模式下,负载均衡器代表整个服务集群接收和响应请求,当流量压力较大时,系统的瓶颈就很容易体现在负载均衡器上。