Linux 基础体系 · 第 72/85 篇。示例面向现代主流 Linux 发行版;发行版差异、权限和生产风险会明确说明。
Linux Keepalived 与 VRRP:虚拟 IP、健康检查、切换和脑裂边界
1. 先区分三个概念:VRRP、Keepalived 和虚拟 IP
**VRRP(Virtual Router Redundancy Protocol,虚拟路由器冗余协议)**是一种节点协作协议。多个真实主机构成一个逻辑上的“虚拟路由器”,对外使用同一个虚拟 IP(Virtual IP,VIP)和虚拟 MAC。正常情况下只有一个节点承担转发或服务入口,其他节点处于备用状态。
Keepalived是 Linux 上常用的用户态高可用程序。它实现了 VRRP,并在此基础上提供:
- 虚拟 IP 的添加和删除;
- VRRP 报文发送与接收;
- 主备状态机;
- 进程、端口、脚本和接口健康检查;
- 状态变化通知;
- 与 IPVS、Nginx 等服务协同。
虚拟 IP不是一个独立设备,也不是由交换机自动“漂移”的地址。它最终仍然表现为 Linux 内核接口上的一个地址,例如:
2: ens160:
inet 192.0.2.10/24
inet 192.0.2.100/24 scope global secondary ens160
其中 192.0.2.100 可以是 VIP。当前主节点通过内核把这个地址配置到本机网卡上,备用节点通常不配置它。主备切换时,Keepalived 实际上是在不同节点上执行添加或删除地址,并发送邻居缓存更新报文。
因此,VIP 高可用至少依赖三层机制共同成立:
- VRRP 控制面:节点知道谁是当前 Master;
- Linux 地址和邻居发现数据面:Master 真正持有 VIP,并让局域网更新 ARP 或 NDP;
- 上层服务:Nginx、应用进程或路由转发功能确实可用。
只实现其中一层并不能得到完整的高可用。
2. VRRP 解决的是什么问题
假设客户端访问:
http://192.0.2.100/
后端有两台入口服务器:
node-a: 192.0.2.11
node-b: 192.0.2.12
VIP: 192.0.2.100
客户端并不需要知道当前由哪台服务器处理请求。它只需要通过 ARP 查询:
谁拥有 192.0.2.100?
当前 Master 回答:
192.0.2.100 is-at <Master 的 MAC>
之后客户端把目的 MAC 写成 Master 的 MAC,IP 目的地址仍然是 VIP。
当 node-a 故障,node-b 成为 Master 后,它会发送 Gratuitous ARP(无偿 ARP,GARP),大意是:
192.0.2.100 is-at <node-b 的 MAC>
客户端和交换机的相关邻居缓存随后更新,新的连接就会到达 node-b。
这里有一个容易被忽略的事实:VIP 切换主要改变的是二层邻居解析结果,不是客户端的 IP 路由表。同一子网中的客户端仍然访问同一个 IP,只是这个 IP 对应的 MAC 发生了变化。
IPv6 使用 NDP(Neighbor Discovery Protocol,邻居发现协议)代替 ARP,Keepalived 会通过相关的邻居通告让网络重新学习 VIP 所在节点。
3. VRRP 的报文与网络前提
VRRP 的典型网络属性如下:
- IPv4 VRRP 使用组播地址
224.0.0.18; - IPv6 VRRP 使用组播地址
ff02::12; - IP 协议号是
112,不是 TCP,也不是 UDP; - VRRP 报文通常要求 TTL 或 Hop Limit 为 255;
- 典型部署要求参与节点位于同一个二层广播域;
- VIP 通常必须属于该二层网络所在的子网。
因此,下面这些条件必须单独验证:
ip addr show dev ens160
ip route
ip link show ens160
如果节点的地址是:
node-a: 192.0.2.11/24
node-b: 192.0.2.12/24
VIP: 192.0.2.100/24
它们看起来属于同一个 /24,但这并不自动证明二层连通。仍然可能存在:
- 交换机端口隔离;
- VLAN 配置错误;
- 防火墙丢弃协议号 112;
- 组播被交换机或云平台过滤;
- VRRP 报文进入了错误的 network namespace;
- 云环境禁止用户直接使用 GARP 或虚拟 MAC。
可以使用 tcpdump 检查是否真的看到 VRRP:
sudo tcpdump -ni ens160 'ip proto 112 or arp'
正常情况下,Master 周期性发送 VRRP 广告报文;切换时,除了 VRRP 状态变化,还应看到新的 Master 发送 ARP 更新。
Keepalived 支持单播 VRRP 配置,适用于某些不支持组播的网络,但单播只改变控制报文的传输方式,不能自动解决 VIP 的二层可达性。跨三层部署时,即使两个节点能够通过单播互相探测,客户端的 ARP、路由和云平台地址绑定仍然可能不成立。
4. VRRP 的状态机
VRRP 中最重要的角色是:
- Master:当前拥有 VIP,并发送 VRRP 广告;
- Backup:不主动拥有 VIP,监听 Master 的广告;
- Init:尚未完成初始化,尚未进入稳定的 Master 或 Backup 状态。
一个简化的状态变化如下:
stateDiagram-v2
[*] --> Init
Init --> Master: 选举后优先级最高\n或配置为唯一可用节点
Init --> Backup: 收到更高优先级 Master 广告
Backup --> Master: Master_Down_Interval 超时
Master --> Backup: 收到更高优先级节点广告且允许抢占
Master --> Backup: 管理员停止或发送优先级 0
Backup --> Master: 抢占延迟结束
4.1 Master 做什么
Master 的主要工作是:
- 在接口上配置 VIP;
- 发送 VRRP Advertisement;
- 响应局域网对 VIP 的 ARP 或 NDP 查询;
- 在服务检查失败时降低自己的有效优先级,或者主动退出;
- 在停止时尽量发送优先级为 0 的报文,通知 Backup 尽快接管。
优先级为 0 的报文表示当前 Master 正在离开服务。它不能保证一定送达,因为主机可能已经断电、内核已经崩溃或链路已经断开。
4.2 Backup 做什么
Backup 通常不应持有 VIP。它会:
- 监听来自 Master 的 VRRP 广告;
- 根据优先级和定时器判断 Master 是否仍然有效;
- 在 Master 超时后竞争成为新的 Master;
- 成为 Master 后添加 VIP,并发送邻居缓存更新;
- 如果发现更高优先级的 Master 且允许抢占,则让出 VIP。
4.3 如何选出 Master
优先级越高,越倾向于成为 Master。一个典型配置是:
node-a priority = 150
node-b priority = 100
当两台节点都正常通信时,node-a 成为 Master。
如果优先级相同,VRRP 还需要一个确定性的决胜规则,通常根据接口地址比较。工程上不应依赖“相同优先级也没关系”,应直接为节点设置不同优先级,使意图清晰。
优先级并不是永久固定的。健康检查可以调整有效优先级。例如:
基础优先级 = 150
Nginx 检查失败扣减 = 50
有效优先级 = 100
如果备用节点有效优先级仍为 120,它就可能接管 VIP。
5. 切换时间如何计算
VRRP 不是“收到心跳就永不切换”。Backup 在一段时间内没有收到合法广告后,才认为 Master 失效。
常见 VRRP 计算关系是:
其中:
Advertisement_Interval是 Master 发送广告的间隔;Priority是 Backup 的优先级;Master_Down_Interval是 Backup 等待 Master 的时间。
例如:
Advertisement_Interval = 1 秒
Backup Priority = 100
则:
所以:
这只是 VRRP 控制面开始接管的时间。真实业务恢复时间还包括:
- Keepalived 状态切换;
- VIP 添加;
- GARP 或 NDP 更新;
- 客户端邻居缓存刷新;
- Nginx 或应用是否已经启动;
- TCP 连接重新建立;
- 上游服务连接池恢复。
因此不能把“VRRP 超时约 3.6 秒”直接等同于“业务在 3.6 秒内完全恢复”。
降低广告间隔可以缩短检测时间,但会增加控制报文频率,并不能消除网络收敛、客户端缓存和应用恢复时间。生产环境应通过故障注入测量实际结果,而不是只根据公式估计。
6. 抢占、回切与连接影响
假设:
node-a priority = 150
node-b priority = 100
node-a 原来是 Master,后来故障,node-b 接管。此时 node-a 恢复:
- 如果允许抢占,
node-a通常会重新成为 Master; - 如果禁止抢占,
node-b可以继续持有 VIP; - 如果设置抢占延迟,
node-a会等待一段时间再回切。
抢占有两个常见风险。
第一,节点刚恢复时服务可能尚未完全准备好,但由于优先级更高,它立即夺回 VIP。可以使用 preempt_delay 或启动阶段的健康检查降低这种风险。
第二,频繁故障会导致 VIP 来回切换,也就是 flap。假设健康检查周期很短、没有 fall 和 rise 稳定次数,服务瞬时超时就可能触发切换。切换配置应当包含一定的滞后:
第一次失败:记录失败
连续多次失败:降低优先级或触发切换
连续多次成功:恢复有效优先级
VIP 切换通常不会迁移已有 TCP 连接。旧 Master 上的连接状态、Nginx 工作进程状态和内核连接跟踪状态不会自动复制到新 Master。结果可能是:
- 已建立连接被重置;
- 长连接断开;
- 客户端自动重试后恢复;
- 连接到后端的会话丢失。
VRRP 解决的是入口地址的可用性,不是连接状态复制。
7. Keepalived 配置示例
以下示例假设:
接口:ens160
node-a:192.0.2.11
node-b:192.0.2.12
VIP:192.0.2.100
VRID:51
在两台机器上安装 Keepalived。不同发行版包名通常相同,但服务名称和配置路径应以发行版为准:
sudo apt install keepalived
# 或
sudo dnf install keepalived
配置文件通常是:
/etc/keepalived/keepalived.conf
7.1 node-a 配置
global_defs {
router_id LVS_NODE_A
script_user root
enable_script_security
}
vrrp_script chk_nginx {
script "/usr/local/sbin/check-nginx.sh"
interval 2
timeout 1
fall 3
rise 2
weight -50
}
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 150
advert_int 1
virtual_ipaddress {
192.0.2.100/24 dev ens160
}
track_script {
chk_nginx
}
notify_master "/usr/local/sbin/keepalived-master.sh"
notify_backup "/usr/local/sbin/keepalived-backup.sh"
notify_fault "/usr/local/sbin/keepalived-fault.sh"
}
7.2 node-b 配置
node-b 的主体配置相同,但修改:
global_defs {
router_id LVS_NODE_B
script_user root
enable_script_security
}
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 100
advert_int 1
virtual_ipaddress {
192.0.2.100/24 dev ens160
}
track_script {
chk_nginx
}
}
将两台节点都设置为 state BACKUP 通常比一台写 MASTER、一台写 BACKUP 更不容易产生误解,因为真正的选举仍由优先级决定。state MASTER 主要影响启动初始状态,不能代替 VRRP 选举。
配置文件权限必须限制为 root 可写:
sudo chown root:root /etc/keepalived/keepalived.conf
sudo chmod 600 /etc/keepalived/keepalived.conf
启动前检查配置。Keepalived 的具体检查选项可能随版本变化,常见方式是:
sudo keepalived -t -f /etc/keepalived/keepalived.conf
然后启动:
sudo systemctl enable --now keepalived
sudo systemctl status keepalived
验证 VIP:
ip -br addr show dev ens160
预期只有当前 Master 显示:
ens160 UP 192.0.2.11/24 192.0.2.100/24
Backup 不应显示 VIP。
auth_pass等 VRRP 认证配置在一些 Keepalived 配置中仍然可见,但不能把它当作现代网络安全边界。它不是对 VRRP 报文进行通用加密,也不能替代网络隔离、访问控制和节点身份保护。
8. 健康检查到底检查什么
Keepalived 的健康检查不是一个单一功能,而是多个层次。
8.1 进程检查
检查 Nginx 进程是否存在:
pgrep -x nginx >/dev/null
这只能证明某个进程存在,不能证明:
- Nginx 正在监听正确地址;
- 配置已经加载成功;
- TLS 证书可用;
- upstream 可达;
- 应用返回正确内容。
8.2 端口检查
可以检查 TCP 端口:
timeout 1 bash -c '</dev/tcp/127.0.0.1/443'
它比进程检查更接近服务入口,但仍然不能证明 HTTP 请求能够成功处理。
8.3 应用检查
一个更有意义的检查可以请求本地健康接口:
#!/bin/sh
set -eu
code=$(
curl --fail --silent --show-error \
--max-time 1 \
--output /dev/null \
--write-out '%{http_code}' \
http://127.0.0.1/healthz
)
[ "$code" = "200" ]
保存为:
/usr/local/sbin/check-nginx.sh
并设置:
sudo chown root:root /usr/local/sbin/check-nginx.sh
sudo chmod 700 /usr/local/sbin/check-nginx.sh
脚本必须具有确定的退出码:
0:检查成功;- 非
0:检查失败。
fall 3 表示连续失败若干次后才认为故障,rise 2 表示连续成功若干次后才恢复。具体有效优先级如何因权重变化,应结合当前 Keepalived 版本的手册验证;使用负权重降低故障节点的竞争优先级是常见配置方式。
8.4 检查对象的边界
如果 Nginx 返回 200,但 Nginx 到后端的所有请求都失败,那么“检查 Nginx 进程”可能误判为健康。反过来,如果检查接口依赖一个偶发不稳定的外部系统,又可能造成不必要的 VIP 切换。
检查应尽量回答这个问题:
当前节点是否能够承担通过 VIP 进入的真实业务?
但检查脚本也不能执行过重的业务流程,否则健康检查本身会成为负载来源。
9. 健康检查失败后的因果链
以 node-a 为当前 Master、node-b 为 Backup 为例:
sequenceDiagram
participant C as Client
participant A as node-a
participant B as node-b
participant S as Backend
C->>A: 请求 VIP
A->>S: 转发请求
B-->>B: 健康检查失败
B-->>A: 仍收到 VRRP 广告
A-->>B: VRRP 广告
Note over A,B: node-a 的 Nginx 也可能失败
A-->>B: 广告停止或有效优先级降低
B->>B: Master_Down_Interval 到期
B->>B: 添加 VIP
B-->>C: GARP/NDP 更新
C->>B: 新连接访问 VIP
B->>S: 转发请求
这里有两种不同的失败路径:
路径一:Master 主机直接宕机
Master 不再发送广告,Backup 等待超时后接管。这个路径通常比较可靠,因为故障节点已经不能继续处理请求。
路径二:Master 主机仍然活着,但服务异常
例如:
- Nginx 进程仍在,但 worker 全部卡死;
- 本机到后端的路由异常;
- TLS 配置加载错误;
- 服务端口仍在监听,但返回 503。
这时必须依赖健康检查。健康检查失败后,Keepalived 可以:
- 降低有效优先级,使另一个节点抢占;
- 进入故障状态;
- 执行通知脚本;
- 删除 VIP,防止继续接收流量。
如果健康检查只检查 VRRP 进程或网卡,服务异常可能不会触发切换。
10. 与 Nginx 反向代理的配合
最简单的做法是让 Nginx 在两台机器上都监听通配地址:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_pool;
}
}
即使 Backup 没有 VIP,Nginx 也能启动,但它不会收到发往 VIP 的流量。成为 Master 后,VIP 添加到接口,流量即可进入 Nginx。
如果配置为:
server {
listen 192.0.2.100:80;
}
则 Backup 在没有 VIP 时可能无法绑定地址。可以选择:
- 只在持有 VIP 的节点启动 Nginx;
- 使用
net.ipv4.ip_nonlocal_bind=1,允许绑定本机当前不存在的地址; - 使用通知脚本在 Master 状态启动服务,在 Backup 状态停止服务;
- 让 Nginx 监听
0.0.0.0,通过 VIP 负责流量入口。
ip_nonlocal_bind 的示例:
sudo sysctl -w net.ipv4.ip_nonlocal_bind=1
持久化配置:
net.ipv4.ip_nonlocal_bind = 1
但这不是无条件更优的选择。它会允许进程绑定本机尚未拥有的地址,可能掩盖 VIP 未正确接管的问题。配置变化后应验证:
ss -ltnp
curl --resolve example.com:80:192.0.2.100 http://example.com/healthz
Keepalived 的通知脚本适合执行服务编排,但脚本必须幂等、快速并且不依赖 VIP 自己才能访问。例如,notify_master 中启动 Nginx 时,应先检查配置:
#!/bin/sh
set -eu
/usr/sbin/nginx -t
systemctl start nginx
如果 nginx -t 失败,脚本不应假装服务已经恢复。生产环境还需要明确:健康检查失败时是仅降低 VRRP 优先级,还是同时停止服务、删除 VIP。两者的故障表现不同,不能只依赖默认行为。
11. VIP 切换时 Linux 内核做了什么
成为 Master 后,Keepalived 通常通过 Netlink 请求内核执行类似操作:
ip addr add 192.0.2.100/24 dev ens160
离开 Master 时则相当于:
ip addr del 192.0.2.100/24 dev ens160
管理员可以观察地址事件:
sudo ip monitor address
也可以检查当前地址:
ip -details addr show dev ens160
注意,手工执行 ip addr add 只能改变本机地址,不能构成完整的 VRRP 接管。还需要:
- 通知局域网更新 ARP 或 NDP;
- 确认交换机允许新的 MAC;
- 确认上游路由能够把流量送到该二层网络;
- 确认应用已经监听并能够处理请求。
手工添加 VIP 还可能与 Keepalived 状态机冲突。测试时若执行过:
sudo ip addr add 192.0.2.100/24 dev ens160
应在测试结束后删除,或者重启 Keepalived 重新收敛:
sudo ip addr del 192.0.2.100/24 dev ens160
生产环境不要把临时 ip 命令当作长期配置管理手段。
12. GARP、ARP 缓存与“切换成功但访问仍失败”
Keepalived 切换后,即使 ip addr 已经显示 VIP,客户端也可能短时间继续把流量发给旧 Master。这是因为客户端或交换机仍然缓存着旧的:
192.0.2.100 -> old MAC
GARP 的作用是主动刷新这些缓存,但它并不保证所有设备都立即接受:
- 某些交换机对 MAC 移动有保护策略;
- 某些云平台不允许用户直接宣告地址;
- 客户端可能忽略或延迟更新 ARP;
- 中间设备可能有静态 ARP;
- 多个网络设备可能存在不同的缓存生命周期。
诊断时可以分别查看本机和远端:
ip neigh show 192.0.2.100
sudo tcpdump -ni ens160 arp
从客户端执行:
arp -n
# 或
ip neigh show
如果本机已经持有 VIP,但客户端仍访问旧节点,应重点检查 GARP、交换机 MAC 表和云平台网络限制,而不是继续修改 VRRP 优先级。
13. IPv4、IPv6 和路由边界
IPv4 的 VIP 依赖 ARP,IPv6 的 VIP 依赖 NDP。两者都要求地址的前缀、接口和上游网络设计正确。不要因为 IPv4 VRRP 已经工作,就假设 IPv6 会自动工作。
例如,IPv6 配置可能包含:
virtual_ipaddress {
2001:db8:10::100/64 dev ens160
}
是否需要显式设置 VRRP 版本、是否允许 IPv6 组播、邻居通告行为如何,取决于 Keepalived 版本和发行版打包方式,部署前应检查本机 Keepalived 手册及实际日志。
VIP 也不等于路由高可用。对于反向代理入口:
客户端 -> VIP -> Nginx -> 后端
VIP 只处理客户端到入口的寻址。后端方向仍然受到:
- 默认路由;
- 策略路由;
- 多路由表;
- VRF;
- ECMP;
- 反向路径检查;
- 防火墙状态跟踪;
的影响。
例如,备用节点虽然成功接管 VIP,但它到后端没有正确路由,结果是客户端请求已经到达新 Master,却仍然全部失败。此时应检查:
ip route get <backend-ip> from 192.0.2.100
ip rule
ip route show table main
ip route show table all
如果存在非对称路由,Linux 的严格反向路径检查可能丢弃报文。可以查看:
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.ens160.rp_filter
调整 rp_filter 必须基于实际路由设计进行,不能把关闭反向路径检查作为普遍修复手段。相关问题应结合策略路由和接口级配置验证。
14. 脑裂是什么
**脑裂(split brain)**是指多个节点都认为自己是当前 Master,并同时持有同一个 VIP。
它不是“两个节点优先级一样”这么简单。脑裂的必要条件是:节点之间失去足够的控制面通信,但它们仍然能够继续运行并服务客户端。
典型过程如下:
正常:
node-a Master,持有 VIP
node-b Backup,不持有 VIP
控制链路中断:
node-a 收不到 node-b,但继续服务
node-b 收不到 node-a,等待超时
错误结果:
node-a 继续认为自己是 Master
node-b 也升级为 Master
两者同时添加 VIP
在同一二层网络中,两个节点都发送 GARP,客户端可能看到:
192.0.2.100 -> MAC_A
192.0.2.100 -> MAC_B
192.0.2.100 -> MAC_A
...
于是出现:
- ARP 缓存来回变化;
- 连接随机进入不同节点;
- 一些客户端访问成功,另一些失败;
- Nginx 日志分散在两台主机;
- 长连接和会话表现不稳定;
- 交换机可能报告 MAC flapping。
更危险的是,如果入口服务后面连接的是有状态系统,两个节点同时执行写操作可能造成数据冲突。VRRP 本身不会保护数据库、文件系统或应用状态。
15. 为什么优先级不能解决脑裂
优先级只有在节点能够互相看到 VRRP 广告时才有效。
设:
node-a priority = 150
node-b priority = 100
在通信正常时,node-a 能够让 node-b 知道自己仍然是 Master。若链路分区使两者都收不到对方报文:
node-a不会收到更高优先级竞争者;node-b也不会收到任何 Master 广告;node-b超时后会成为 Master;node-a继续保持 Master。
因此,优先级解决的是可见节点之间的选举顺序,不能解决节点互相不可见时谁有资格继续服务。
单播 VRRP 也不能从根本上解决脑裂。它可能让控制报文绕过组播限制,但如果网络存在单向故障:
node-a 能发给 node-b
node-b 不能发给 node-a
两个节点对对方状态的判断仍可能不一致。更复杂的多路径网络还可能产生部分可达、部分不可达的情况。
16. 同一二层和不同二层中的脑裂表现不同
如果两个脑裂节点位于同一二层:
- 相同 VIP 会产生 ARP 冲突;
- MAC 地址可能在交换机端口之间快速移动;
- 故障通常比较明显,但影响面可能很大。
如果两个节点位于不同二层或不同数据中心:
- 它们可能都持有相同 VIP;
- 各自本地网络可能都认为该 VIP 合法;
- 是否冲突取决于上游路由、BGP、云平台地址绑定和客户端路径;
- 两个区域可能同时接收真实流量。
“不同网段所以不会脑裂”是错误理解。不同网段可能减少 ARP 冲突,却不能阻止双主,也不能阻止两个节点同时写入共享状态。
跨三层或跨数据中心的高可用通常需要其他机制,例如:
- 路由协议撤销和发布;
- 云平台的浮动 IP 或 API 绑定;
- 分布式仲裁;
- 共享存储 fencing;
- 应用层租约;
- 数据库自身的主节点选举。
Keepalived 可以参与其中,但 VRRP 单独不提供法定人数(quorum)或强制隔离(fencing)。
17. 脑裂检测与恢复
日志是第一证据:
sudo journalctl -u keepalived -f
重点观察:
- 当前状态是否在
MASTER和BACKUP之间频繁切换; - 是否出现多个节点都宣布成为 Master;
- 健康检查是否反复失败;
- 是否能收到 VRRP 报文;
- 是否发生优先级变化;
- 是否执行了通知脚本。
同时在两台机器上执行:
ip -br addr show dev ens160
ip neigh
sudo tcpdump -ni ens160 'ip proto 112 or arp'
若两台机器都显示 VIP,先不要继续重启或反复修改优先级。应先确认哪一台具备真实服务能力,再隔离错误节点:
sudo systemctl stop keepalived
必要时还应停掉 Nginx 或应用,避免双主继续处理写请求。恢复网络后,确认:
# 只有预期 Master 持有 VIP
ip addr show dev ens160
# VRRP 报文方向恢复
sudo tcpdump -ni ens160 'ip proto 112'
# 客户端的邻居缓存指向正确 MAC
ip neigh show <VIP>
如果脑裂期间存在数据库或文件写入,VIP 恢复并不意味着数据已经一致。必须单独检查应用状态、数据库复制状态和业务幂等性。
18. 防火墙和安全边界
防火墙至少要考虑:
- VRRP 的 IP 协议号
112; - VRRP 组播地址;
- 管理和监控端口;
- 健康检查依赖的本地或后端访问;
- Nginx 对外监听端口。
可以用以下命令查看本机是否实际收到 VRRP:
sudo tcpdump -ni ens160 'ip proto 112'
如果完全没有报文,优先检查接口、VLAN、组播和防火墙,而不是先修改 priority。
VRRP 控制报文不应被认为是强身份认证信道。攻击者如果能够注入或伪造 VRRP 报文,可能影响选举;如果攻击者能够访问同一广播域,还可能直接干扰 ARP。因此生产环境需要:
- 限制二层接入;
- 控制管理权限;
- 限制 Keepalived 配置和检查脚本的写权限;
- 监控异常 VRRP 和 MAC 变化;
- 不在健康检查脚本中拼接未经验证的外部输入。
enable_script_security 和 root 脚本权限控制可以降低脚本路径被替换等风险,但不能替代主机加固。
19. 一个可验证的故障演练
不要只通过“拔电源”验证。应分别测试控制面、服务面和数据面。
19.1 测试正常状态
在两台节点上执行:
systemctl is-active keepalived
ip -br addr show dev ens160
curl --max-time 2 http://192.0.2.100/healthz
预期:
- 一台节点是 Master 并拥有 VIP;
- 另一台节点是 Backup 且没有 VIP;
- VIP 请求能够成功。
19.2 测试服务故障
在当前 Master 上停止 Nginx:
sudo systemctl stop nginx
观察:
sudo journalctl -u keepalived -f
ip -br addr show dev ens160
如果健康检查正确,经过 fall 次数和选举时间后,Backup 应接管 VIP。若没有切换,应检查:
- 健康脚本是否可执行;
- 脚本退出码是否正确;
- Keepalived 是否加载了
track_script; - 权重变化是否足以让对端优先级更高;
- Nginx 停止后本地检查是否仍然命中其他服务。
19.3 测试主机故障
安全方式是停止 Keepalived:
sudo systemctl stop keepalived
这通常会触发优先级为 0 的通知,备用节点应更快接管。然后恢复:
sudo systemctl start keepalived
再观察是否发生预期回切。
19.4 测试网络分区
网络分区是脑裂测试,风险最高。不要在没有隔离客户端、写入流量和恢复方案的生产环境中直接执行。测试目标不是“VIP 最终能否访问”,而是确认:
- 哪些故障会导致双主;
- 监控能否识别双主;
- 应用是否有写入保护;
- 恢复时谁被安全隔离;
- 客户端 ARP 和交换机 MAC 表多久收敛。
20. 常见误解
误解一:VIP 在两台机器上预先都配置好就能高可用
如果两台机器同时持有同一个 VIP,就已经绕过了 VRRP 的主备语义。除非上层明确设计了 Anycast 或其他多活模型,否则这通常会造成地址冲突。
误解二:Keepalived 能保证服务可用
Keepalived 只能根据可观察信号改变 VIP 归属。健康检查写错、检查层次过低或后端不可达时,可能出现“VIP 正常但业务失败”。
误解三:切换后已有连接会自动继续
VIP 和 TCP 连接状态不是同一个对象。地址可以切换,连接状态不会自动迁移。
误解四:两个节点能 ping 通,就说明 VRRP 正常
ping 测试的是 ICMP 可达性,不等于协议号 112 的 VRRP 报文、组播、ARP 更新和服务流量都正常。必须使用 tcpdump、ip monitor 和实际 VIP 请求分别验证。
误解五:脑裂只是 VIP 冲突
VIP 冲突是可见症状,真正的风险是两个节点同时认为自己有服务资格。对于无状态 Nginx,表现可能是连接抖动;对于数据库、队列或共享文件,可能演变为数据破坏。
21. 诊断顺序
遇到“VIP 不切换”时,可以按故障路径检查:
# 1. Keepalived 是否运行
systemctl status keepalived
# 2. 配置和日志是否显示错误
journalctl -u keepalived -b
# 3. VIP 当前在哪台机器
ip -br addr
# 4. 是否收到 VRRP 报文
tcpdump -ni ens160 'ip proto 112'
# 5. 是否发生 ARP 更新
tcpdump -ni ens160 arp
# 6. 服务是否真正可用
curl --max-time 2 http://127.0.0.1/healthz
curl --max-time 2 http://<VIP>/healthz
# 7. 到后端的路由是否正确
ip route get <backend-ip> from <VIP>
# 8. 是否存在策略路由或反向路径检查问题
ip rule
ip route show table all
sysctl net.ipv4.conf.all.rp_filter
不同现象对应的故障层次不同:
- 没有 VRRP 报文:接口、VLAN、组播、协议号 112、防火墙;
- VIP 已添加但客户端仍访问旧节点:GARP、ARP 缓存、交换机 MAC 学习;
- VIP 已切换但 HTTP 失败:Nginx、监听地址、证书、后端路由或防火墙;
- 两台都持有 VIP:控制面分区、单向链路、错误的手工配置或脑裂;
- 频繁回切:健康检查抖动、抢占、权重和
rise/fall参数不匹配。
22. 设计边界
Keepalived 与 VRRP 很适合以下场景:
同一二层网络
两台或少量入口节点
一个稳定的 VIP
无状态或可重试的反向代理
应用状态存储在独立的高可用系统中
它不单独解决以下问题:
- 数据库主从一致性;
- 跨数据中心仲裁;
- 共享存储脑裂保护;
- TCP 连接状态迁移;
- 云平台对浮动 IP 的控制;
- 上游和后端路由的自动收敛;
- 两个节点同时成为 Master 时的强制隔离。
因此,一个完整的高可用设计应把因果链写清楚:
VRRP 广告正常
-> Backup 知道 Master 存活
-> Master 持有 VIP
-> ARP/NDP 指向 Master
-> Nginx 监听并通过健康检查
-> 后端路由和策略允许转发
-> 客户端能够重试或恢复连接
其中任意一环失败,最终现象都可能是“VIP 在,但业务不可用”。而当 VRRP 控制面分区时,真正的边界是:VRRP 可以选举可见节点,却不能在不可见节点之间提供仲裁和 fencing。这正是 Keepalived 与 VRRP 能力的核心边界。
系列导航与关联阅读
- 系列入口:Linux 完整学习路线:从内核与文件系统到网络、性能和生产运维
- 上一篇:Linux Nginx 反向代理:进程模型、TLS、负载均衡、限流和日志
- 下一篇:SELinux 完整基础:Label、Type Enforcement、Policy、布尔值和排障
- 延伸:Linux 路由深入:多表、策略路由、ECMP、VRF 和反向路径检查
官方资料
本文依据 Linux 内核、systemd 与主流发行版官方文档重新梳理;正文与实验由 WR BLOG 编写。

评论
0 条讨论