本文面向寻求构建高可用、高性能网络入口的中高级工程师。我们将深入探讨如何利用 LVS(Linux Virtual Server)和 Keepalived 这一经典组合,构建一个生产级的双机热备负载均衡集群。本文并非简单的配置罗列,而是从 Netfilter 内核钩子、VRRP 协议原理出发,剖析 LVS-DR 模式的实现细节、经典的“脑裂”问题,并最终给出一套可落地、可演进的架构方案,旨在帮助读者建立对四层负载均衡与高可用体系的深刻理解。
现象与问题背景
在任何一个有一定规模的线上服务中,单点故障(Single Point of Failure, SPOF)都是架构设计中的天敌。假设我们有一个业务集群,由多台应用服务器(Real Server, RS)构成,最初我们可能通过 DNS 轮询进行简单的流量分发。这种方式虽然简单,但存在两个致命问题:首先,当某台 RS 宕机时,DNS 缓存会导致用户流量在一段时间内仍然被错误地导向故障节点;其次,它无法根据服务器的实际负载进行动态调度。
为了解决这个问题,业界引入了负载均衡器(Load Balancer)。一个典型的改进方案是在 RS 集群前部署一台高性能服务器(例如 Nginx 或 HAProxy),作为流量入口。这台服务器根据预设的策略(如轮询、最少连接)将客户端请求分发到后端的 RS。这确实解决了流量分发和后端节点健康检查的问题,但引入了一个新的、更严重的单点故障:这台负载均衡器本身。一旦它宕机,整个业务系统将彻底瘫痪。
因此,我们的核心诉求演变为两个层面:水平扩展(Scale-out)和高可用(High Availability)。我们需要一个既能高效分发流量,又能自我故障转移的入口集群。LVS + Keepalived 正是解决这一经典问题的黄金搭档。LVS 负责提供内核级别的高性能四层负载均衡,而 Keepalived 则通过实现 VRRP 协议,为 LVS 节点提供主备热切换能力,从而消除单点故障。
关键原理拆解:深入内核与网络协议
要真正掌握 LVS 和 Keepalived,我们必须暂时抛开配置文件,深入到它们背后的计算机科学基础原理。这涉及到 Linux 内核的网络堆栈和标准的网络冗余协议。
LVS:内核中的高速公路
LVS,全称 Linux Virtual Server,并非一个用户态的应用程序,而是 Linux 内核的一部分,具体来说是 `ip_vs` (IP Virtual Server) 模块。它工作在 Netfilter 框架之上,通过在内核的数据包处理路径上设置钩子(Hooks)来劫持、修改并转发网络包,从而实现负载均衡。这种在内核态直接处理数据包的方式,避免了用户态与内核态之间频繁的数据拷贝和上下文切换,是 LVS 性能远超 Nginx 等七层负载均衡器的根本原因。
`ip_vs` 主要在 Netfilter 的 `PREROUTING` 链上工作。当一个数据包到达网卡,进入内核协议栈后,`ip_vs` 会检查其目标 IP 和端口。如果匹配预先设定的虚拟服务(Virtual Service),它会根据指定的负载均衡算法(如 rr, wrr, lc, wlc)选择一台后端的 Real Server,然后直接修改数据包的目标 MAC 地址(在DR模式下)或目标 IP 地址(在NAT模式下),并将包转发出去。这个过程对客户端和后端服务器都是透明的。
LVS 的三种核心模式
LVS 的工作模式决定了其网络拓扑和性能表现,其中 DR 模式是生产环境中最常用也是最高效的模式。
- NAT (Network Address Translation) 模式:这是最简单的一种模式。Director 服务器接收到请求包后,将包的目标 IP 修改为选定的 Real Server 的 IP,然后转发出去。当 Real Server 处理完请求返回响应包时,响应包必须再次经过 Director,由 Director 将源 IP 修改回 VIP,再发给客户端。这意味着 Director 成为了出入流量的瓶颈,性能受限于其网卡带宽和 CPU 处理能力。
- TUN (IP Tunneling) 模式:Director 将收到的请求包封装在一个新的 IP 包中(IP-in-IP),然后发送给选定的 Real Server。Real Server 解封装后处理请求,并将响应包直接发送给客户端,无需再经过 Director。这种模式打破了 Director 必须和 Real Server 在同一物理网络的限制,适用于跨地域的负载均衡,但封装和解封装会带来一定的性能开销。
- DR (Direct Routing) 模式:这是性能最高的模式。Director 接收到请求包后,不修改包的 IP 地址,而是直接修改其目标 MAC 地址为选定 Real Server 的 MAC 地址,然后将数据帧在二层网络上转发出去。由于 Real Server 和 Director 共享同一个 VIP(Virtual IP),Real Server 收到包后可以正常处理,并将响应包直接发送给客户端(因为源 IP 就是客户端 IP,目标 IP 是 VIP,Real Server 本身也配置了 VIP)。这意味着 Director 只处理入站流量,而出站流量由 Real Server 直接响应,极大地提升了整个集群的吞吐能力。
DR 模式的精髓在于“三角传输”,但它的实现有一个关键的工程挑战:ARP 问题。由于 Director 和所有 Real Server 都配置了相同的 VIP,当网络中的设备(如网关)发起对 VIP 的 ARP 请求时,可能会有多台机器响应,造成 ARP 冲突和通信混乱。解决办法是在所有 Real Server 上抑制对 VIP 的 ARP 响应,同时配置 lo 环回接口来接收发往 VIP 的数据包。
VRRP:虚拟路由冗余协议的博弈
VRRP (Virtual Router Redundancy Protocol, RFC 5798) 是一种网络协议,旨在为局域网中的一组路由器(或主机)提供一个虚拟的、高可用的网关地址。Keepalived 正是利用了 VRRP 来实现 LVS Director 的主备切换。
VRRP 的工作机制可以理解为一场简单而优雅的选举博弈:
- 角色:在一个 VRRP 组(由 `virtual_router_id` 标识)中,有两类角色:一个 MASTER 和一个或多个 BACKUP。
- 虚拟 IP (VIP):整个组共享一个 VIP,这个 VIP 就是对外提供服务的地址。在任何时刻,只有 MASTER 节点会持有并响应对这个 VIP 的网络请求。
- 选举与心跳:选举依据是优先级(Priority),一个 0-255 的整数,数值越大优先级越高。初始状态下,优先级最高的节点会成为 MASTER。成为 MASTER 后,它会周期性地(由 `advert_int` 定义)向一个特定的组播地址(`224.0.0.18`)发送 VRRP 通告报文,宣告自己的存活。
- 抢占(Preemption):如果一个高优先级的 BACKUP 节点启动,或者从故障中恢复,它会发现当前 MASTER 的优先级比自己低。如果开启了抢占模式(`preempt`),它就会立即“抢占” MASTER 的位置,成为新的 MASTER。
- 故障切换:所有的 BACKUP 节点都在静默监听这些组播通告。如果在一定时间内(通常是 3 倍 `advert_int`)没有收到 MASTER 的通告,它们就认为 MASTER 已经宕机。此时,所有 BACKUP 节点中优先级最高的那个会转变为 MASTER,接管 VIP,并开始发送自己的 VRRP 通告。这个过程完成了故障的自动切换。
Keepalived 将 LVS 的配置与 VRRP 的状态机绑定。当一个节点成为 MASTER 时,Keepalived 会自动执行脚本添加 VIP 到网络接口,并加载 `ipvs` 规则;当它转为 BACKUP 时,则会移除 VIP 和 `ipvs` 规则。这样就实现了业务层面的无缝切换。
系统架构总览
基于以上原理,一个典型的 LVS-DR + Keepalived 双机热备集群架构如下:
我们设定两台 LVS Director 服务器,LVS-MASTER (192.168.1.10) 和 LVS-BACKUP (192.168.1.11)。它们共同对外提供一个虚拟 IP (VIP) 192.168.1.100。后端有三台 Real Server(192.168.1.21, 192.168.1.22, 192.168.1.23),例如运行着 Nginx 服务。
- 正常状态:LVS-MASTER 的优先级更高(如 150),它成为 MASTER 角色。它会拥有 VIP 192.168.1.100,并周期性地发送 VRRP 组播心跳。LVS-BACKUP 的优先级较低(如 100),作为 BACKUP 角色,静默监听心跳。
- 流量路径:客户端请求发送到 VIP 192.168.1.100。请求到达 LVS-MASTER 后,LVS-DR 模块根据负载均衡算法选择一台 RS(如 192.168.1.21),将请求数据帧的目标 MAC 地址修改为 RS1 的 MAC,然后在二层网络转发。
- 响应路径:RS1 收到数据包,处理后直接将响应包通过网关发回给客户端,无需经过 LVS-MASTER。
- 故障切换:当 LVS-MASTER 宕机(或网络故障导致心跳中断),LVS-BACKUP 在超时后将无法收到 VRRP 心跳。它会立即将自己的状态切换为 MASTER,通过发送免费 ARP(Gratuitous ARP)宣告自己接管了 VIP 192.168.1.100,并加载 `ipvs` 规则开始转发流量。交换机会更新其 MAC 地址表,将发往 VIP 的流量导向 LVS-BACKUP。整个切换过程对客户端是透明的,通常在秒级完成。
这个架构有效地结合了 LVS-DR 的高性能和 Keepalived 的高可用性,构成了一个健壮的前端流量入口。
核心模块设计与实现:配置与脚本的艺术
理论的深度最终要通过精准的工程实践来体现。下面我们将展示关键的配置文件和内核参数调整,这正是从“知道”到“做到”的鸿沟。
Keepalived 核心配置 (`keepalived.conf`)
这是整个系统的“大脑”,配置必须精确无误。下面是 LVS-MASTER 节点的配置示例。
! /etc/keepalived/keepalived.conf on LVS-MASTER (192.168.1.10)
global_defs {
notification_email {
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL_MASTER # 标识节点,便于识别
}
# VRRP 实例定义
vrrp_instance VI_1 {
state MASTER # 初始状态为 MASTER
interface eth0 # VRRP 通信使用的网络接口
virtual_router_id 51 # VRRP 组 ID,主备必须一致
priority 150 # 优先级,MASTER 高于 BACKUP
advert_int 1 # VRRP通告间隔,单位秒
preempt # 允许抢占
authentication {
auth_type PASS
auth_pass 1111 # 简单的认证密码,主备必须一致
}
# VIP 地址,可以有多个
virtual_ipaddress {
192.168.1.100/24 dev eth0 label eth0:0
}
}
# LVS 虚拟服务定义
virtual_server 192.168.1.100 80 {
delay_loop 6 # 健康检查间隔
lb_algo rr # 负载均衡算法:round-robin
lb_kind DR # LVS 模式:Direct Routing
# persistence_timeout 50 # 会话保持时间,可选
protocol TCP
# 后端 Real Server 1
real_server 192.168.1.21 80 {
weight 1
HTTP_GET {
url {
path "/"
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
# 后端 Real Server 2
real_server 192.168.1.22 80 {
weight 1
HTTP_GET {
url {
path "/"
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
对于 LVS-BACKUP 节点 (192.168.1.11),其配置与 MASTER 基本相同,只需修改两处:
state BACKUPpriority 100(必须低于 MASTER)
这里的极客细节:`virtual_router_id` 是一个看似无害但极其关键的参数。在同一个二层网络中,它必须是唯一的。如果两个不同的 HA 集群错误地使用了相同的 ID,它们会互相干扰,导致无法预测的 VIP 漂移。
LVS-DR 模式的内核魔术
如前所述,DR 模式最大的坑点在于 ARP。我们需要在所有 Real Server 上进行内核参数调整,让它们“闭嘴”,不对 VIP 的 ARP 请求作答,同时又能在本地正确处理发往 VIP 的数据包。
在所有 Real Server 上执行以下操作:
# 1. 配置 VIP 到 lo 环回接口
ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 broadcast 192.168.1.100 up
route add -host 192.168.1.100 dev lo:0
# 2. 修改 sysctl 内核参数以抑制 ARP 响应
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
# 建议将这些参数写入 /etc/sysctl.conf 以便永久生效
# net.ipv4.conf.all.arp_ignore = 1
# net.ipv4.conf.all.arp_announce = 2
# net.ipv4.conf.lo.arp_ignore = 1
# net.ipv4.conf.lo.arp_announce = 2
让我们用极客的方式解读这两个参数:
arp_ignore=1: 当 ARP 请求的目标 IP 是本机配置的 IP 时,仅当该 IP 地址是请求到达的网络接口上的地址时,才回应 ARP 请求。因为 VIP 配置在 `lo` 接口,而 ARP 请求从 `eth0` 进来,所以系统会忽略对 VIP 的 ARP 请求。arp_announce=2: 在对外发送 ARP 请求时,总是使用最适当的本地地址作为源 IP 地址。这意味着当 `eth0` 要对外通信时,它会使用 `eth0` 的 IP 地址,而不是 `lo` 接口上的 VIP 地址。这避免了向外暴露 VIP 的 MAC 地址,从而将 ARP 响应的权力完全交给了 LVS Director。
这两个参数的组合,精妙地解决了 DR 模式下的 ARP 冲突问题,是保证该模式正常工作的基石。
性能优化与高可用设计的对抗性思考
架构设计是一个充满权衡(Trade-off)的过程。LVS+Keepalived 方案虽然成熟,但在部署时依然需要思考几个对抗性问题。
DR 模式的性能优势与代价
我们选择 DR 模式是为了追求极致的性能。它的优势是显而易见的:Director 只处理入向流量,并且是内核态的零拷贝转发,吞吐量几乎可以达到网卡的物理极限。代价则是配置的复杂性。它要求 Director 和所有 Real Server 必须在同一个二层广播域(同一个 VLAN),并且需要对所有 Real Server 进行精细的内核参数和网络配置。相比之下,NAT 模式虽然有性能瓶颈,但配置简单,对后端服务器无特殊要求,在流量不大的场景下也是一个可行的选择。
脑裂(Split-Brain)问题与缓解策略
这是所有主备/主从架构的噩梦。所谓脑裂,是指在主备两个节点之间由于网络故障(例如心跳网络中断,但两个节点本身都还活着),导致 BACKUP 节点误以为 MASTER 已经死亡,从而自己也升级为 MASTER。结果网络中出现了两个 MASTER,都声称自己拥有 VIP。这会导致交换机上的 MAC 地址表疯狂地在两个 Director 的端口之间来回切换(MAC Flapping),造成整个服务严重抖动甚至中断。
Keepalived 本身对脑裂的防御能力有限,但我们可以通过工程手段进行缓解:
- 多路心跳:不要只依赖单一网络路径。可以为 VRRP 心跳配置一个独立的网络接口,甚至通过 Bond 将多个物理网卡绑定,增加心跳网络的冗余。
- 仲裁机制:引入一个或多个“仲裁者”。当一个节点要切换为 MASTER 时,它不仅要判断收不到心跳,还要去尝试 ping 网关或者一个稳定的第三方 IP。只有当“收不到心跳”和“能访问外部网络”两个条件同时满足时,才进行切换。这可以通过 `notify` 脚本实现,在脚本中加入对网关的 ping 检测逻辑。
- Fencing(隔离):这是最彻底的方案。当一个节点确定要成为 MASTER 时,它会通过带外管理(如 IPMI)强制重启或关闭另一个节点,确保旧的 MASTER 彻底离线。Keepalived 本身不支持 Fencing,需要借助 Pacemaker 等更复杂的集群管理软件来实现。
在实践中,最常用的缓解方案是结合多路心跳和网关仲裁。
健康检查的“快”与“慢”
Keepalived 对 Real Server 的健康检查配置(如 `delay_loop`, `connect_timeout`)直接影响故障发现的速度(MTTD)和系统的稳定性。检查间隔设置得太短(快),可以更快地将故障 RS 踢出集群,但可能会因为暂时的网络抖动或 RS 瞬时高负载而造成误判,导致 RS 频繁上下线。检查间隔设置得太长(慢),虽然更稳定,但在 RS 真正宕机后,LVS 会在更长的时间内继续向其转发流量,导致部分用户请求失败。这是一个典型的可用性与稳定性之间的权衡,需要根据业务的容忍度和 RS 的稳定性进行综合调优。
架构演进与落地路径
一个健壮的架构不是一蹴而就的,它应该随着业务的发展而演进。对于 LVS 集群的部署,可以遵循以下路径。
阶段一:单点 LVS-DR
在业务初期,流量不大但已有水平扩展需求时,可以先部署单台 LVS Director。这解决了后端 RS 的负载均衡问题,此时的架构瓶颈是 Director 的单点故障风险。这个阶段的重点是验证 DR 模式的网络配置和业务兼容性。
阶段二:LVS + Keepalived 主备(Active-Passive)
这是本文详述的核心方案。当业务对可用性提出更高要求时,引入第二台 Director 和 Keepalived,组成主备集群。这种模式下,有一半的硬件资源处于备用状态,资源利用率为 50%,但架构简单、稳定可靠,是绝大多数场景下的首选方案。
阶段三:LVS + Keepalived 主主(Active-Active)
为了提升资源利用率,可以考虑主主模式。这通常通过在两台 Director 上配置两个或多个不同的 `vrrp_instance` 来实现。例如,Director A 是 VIP1 的 MASTER 和 VIP2 的 BACKUP,而 Director B 是 VIP1 的 BACKUP 和 VIP2 的 MASTER。这样,两台机器平时都承载着业务流量。这种模式的挑战在于容量规划,必须保证任何一台机器宕机后,剩下的一台有足够的能力承接全部流量(N-1 原则),否则会在故障时发生雪崩。
未来展望:云原生时代的对标
在公有云和容器化大行其道的今天,很多团队会直接选择云厂商提供的负载均衡器(如 AWS 的 NLB/ALB,阿里云的 SLB)或基于 Service Mesh 的流量管理方案(如 Istio Ingress Gateway)。这些方案极大地简化了运维复杂度。然而,LVS+Keepalived 的价值并未消失。首先,在私有化部署、混合云或对成本和性能有极致要求的场景中,它依然是极具竞争力的技术方案。更重要的是,理解 LVS 的内核转发、VRRP 的选举机制、DR 模式的二层技巧以及脑裂等底层问题,能够让你在使用任何高级负载均衡产品时,都具备洞察其底层行为和快速排查疑难杂症的能力。这些跨越时代的核心原理,是每一位资深架构师的必备内功。
延伸阅读与相关资源
-
想系统性规划股票、期货、外汇或数字币等多资产的交易系统建设,可以参考我们的
交易系统整体解决方案。 -
如果你正在评估撮合引擎、风控系统、清结算、账户体系等模块的落地方式,可以浏览
产品与服务
中关于交易系统搭建与定制开发的介绍。 -
需要针对现有架构做评估、重构或从零规划,可以通过
联系我们
和架构顾问沟通细节,获取定制化的技术方案建议。