12.4.4 脑裂检测与防护策略
脑裂是指主备节点在网络分区或健康检查误判时同时处于 MASTER 状态并争抢 VIP,导致业务写入冲突与流量抖动。Keepalived 场景下需识别触发条件:VRRP 链路中断、健康检查脚本误判、交换机 MAC 学习异常、双网卡不一致等。评估后果包括数据库双写、连接闪断与 ARP 冲突。
以下为原理草图(双网卡心跳 + 业务网):
脑裂检测:多信号判定脚本示例#
目标:只有当“业务不可用 + 对端可达 + 本机路由异常”同时出现才触发降级,降低误判。
# /etc/keepalived/scripts/check_brain_split.sh
#!/usr/bin/env bash
# 1) 业务端口探测 2) 对端可达性 3) 默认路由检查
# 返回非0触发降级
SVC_IP="127.0.0.1"
SVC_PORT=8080
PEER_IP="10.0.0.12"
GW_IP="10.0.0.1"
# 业务端口
timeout 2 bash -c "</dev/tcp/${SVC_IP}/${SVC_PORT}" >/dev/null 2>&1
svc_ok=$?
# 对端可达
ping -c1 -W1 "${PEER_IP}" >/dev/null 2>&1
peer_ok=$?
# 默认路由
ip route | grep -q "default via ${GW_IP}"
route_ok=$?
# 多信号判定:业务不可用 + 对端可达 + 路由异常 才触发
if [[ $svc_ok -ne 0 && $peer_ok -eq 0 && $route_ok -ne 0 ]]; then
echo "brain-split risk: svc down, peer reachable, route broken"
exit 1
fi
exit 0
在 keepalived 配置中引用:
# /etc/keepalived/keepalived.conf
vrrp_script chk_brain {
script "/etc/keepalived/scripts/check_brain_split.sh"
interval 2
fall 2
rise 3
weight -20
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
nopreempt
virtual_ipaddress {
192.168.10.100/24
}
track_script {
chk_brain
}
}
命令解释:
- interval:健康检查间隔(秒)。
- fall:连续失败次数达到后判定失败。
- weight:失败时优先级降低值。
- nopreempt:禁用抢占,避免短暂抖动反复切换。
网络层防护:ARP 与 GARP 稳定配置#
# /etc/sysctl.d/99-arp.conf
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.default.arp_announce = 2
# 应用
sysctl -p /etc/sysctl.d/99-arp.conf
# /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_A
}
vrrp_instance VI_1 {
garp_master_delay 2
garp_master_refresh 30
}
预期效果:VIP 变更时 GARP 稳定、减少 ARP 冲突;VIP 不会在非绑定接口响应。
外部仲裁(失联即关闭)#
当检测到与对端完全失联且业务异常时,建议借助外部仲裁(STONITH/IPMI/云控制)确保只有一个节点持有 VIP:
# /etc/keepalived/scripts/fence_ipmi.sh
#!/usr/bin/env bash
# 示例:关机对端(替换为实际BMC信息)
ipmitool -I lanplus -H 10.0.0.20 -U admin -P 'Passw0rd' chassis power off
# keepalived.conf 触发通知
vrrp_instance VI_1 {
notify_master "/etc/keepalived/scripts/fence_ipmi.sh"
}
说明:仅在确诊脑裂风险时触发,防止误关机。
排错与验证命令#
# 查看当前状态
systemctl status keepalived
ip addr show | grep -A2 192.168.10.100
# VRRP 日志
journalctl -u keepalived -f
# 观察 GARP
tcpdump -i eth0 -nn "arp or (udp and port 112)"
# 验证对端可达性
ping -c2 10.0.0.12
常见故障定位:
- 双主:两端均有 VIP → 检查 nopreempt、priority、心跳链路、健康检查脚本返回值。
- 频繁切换:advert_int 过小、脚本抖动 → 增加 fall/rise,完善多信号判定。
- VIP 不可达:ARP 冲突 → 检查 arp_ignore/announce 与 garp_master_*。
演练步骤(可复现)#
- 断开心跳链路:拔掉心跳网卡,观察是否触发切换。
- 模拟业务故障:停止服务进程,验证
track_script降级。 - 恢复业务:启动服务,确认回切策略(是否抢占)。
示例命令:
# 停止业务模拟故障
systemctl stop myapp
# 观察日志与 VIP 变化
journalctl -u keepalived -n 50
ip addr | grep 192.168.10.100
练习#
- 将
check_brain_split.sh改为同时检测数据库端口与磁盘只读状态,并解释返回值逻辑。 - 将
nopreempt移除,分别设置priority为 150/100,观察切换行为并记录日志。 - 使用
tcpdump捕获 GARP,解释每条 ARP 报文的源/目的含义。