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 → 检查 nopreemptpriority、心跳链路、健康检查脚本返回值。
- 频繁切换advert_int 过小、脚本抖动 → 增加 fall/rise,完善多信号判定。
- VIP 不可达:ARP 冲突 → 检查 arp_ignore/announcegarp_master_*

演练步骤(可复现)#

  1. 断开心跳链路:拔掉心跳网卡,观察是否触发切换。
  2. 模拟业务故障:停止服务进程,验证 track_script 降级。
  3. 恢复业务:启动服务,确认回切策略(是否抢占)。

示例命令:

# 停止业务模拟故障
systemctl stop myapp

# 观察日志与 VIP 变化
journalctl -u keepalived -n 50
ip addr | grep 192.168.10.100

练习#

  1. check_brain_split.sh 改为同时检测数据库端口与磁盘只读状态,并解释返回值逻辑。
  2. nopreempt 移除,分别设置 priority 为 150/100,观察切换行为并记录日志。
  3. 使用 tcpdump 捕获 GARP,解释每条 ARP 报文的源/目的含义。