Keepalived切换失败的核心原因是VRRP心跳中断、监控脚本返回值不合规、priority与weight配置错误及VIP未正确绑定。需分层验证:先用tcpdump确认VRRP组播报文可达,再手动执行脚本校验exit码,接着核对weight符号、state设置与vrrp_script声明一致性,最后检查interface名、virtual_ipaddress格式及ip_nonlocal_bind内核参数。

Keepalived 切换失败,核心在于“谁该升主”没判准、“VIP该飘到哪”没执行到位。问题往往不是单一环节崩溃,而是多个配置与运行条件连锁失配。定位关键不在猜,而在分层验证:先看心跳通不通,再看脚本返不返得对,最后看优先级算不算得准。
检查 VRRP 心跳是否真正可达
VRRP 依赖组播通信维持主备感知,中断即失联、失联即误切。不能只 ping 通就认为网络正常。
- 在备节点执行:tcpdump -i eth0 proto 112(替换为实际网卡名),确认能否持续收到主节点发来的 VRRP 报文
- 若无报文,逐项排查:防火墙是否放行 UDP 端口 112、交换机是否转发组播地址 224.0.0.18、两节点 vrrp_mcast_group4 配置是否一致
- 物理链路异常(如网卡 flap、交换机堆叠分裂)也会导致间歇性丢包,需结合 ip link show 和交换机日志交叉验证
验证监控脚本返回值是否严格符合预期
Keepalived 只认 exit 码:0 = 健康,非 0 = 异常。任何中间状态、echo 输出、静默成功,都等于没返回。
- 用 Keepalived 实际运行用户手动执行脚本:sudo -u keepalived /etc/keepalived/check_redis.sh && echo $?
- 停掉 Redis 后重试,确认返回值变为非 0;恢复后必须回到 0 —— 两者都要验证
- 脚本末尾必须显式写 exit 0 或 exit 1,不能依赖上一条命令结果;避免使用 ps | grep keepalived 类逻辑(脚本名含 keepalived 会自我匹配)
核对 priority 与 weight 协同计算是否生效
脚本健康与否,最终要转化为 priority 变化才能触发切换。weight 不带符号、track_script 拼错、state 设置矛盾,都会让权重失效。
- 确认 vrrp_instance 中 state 统一设为 BACKUP,靠 priority + weight 动态升降,避免 MASTER 强制抢占引发脑裂
- vrrp_script 定义块必须在 vrrp_instance 外全局声明,且 track_script 名称与之完全一致,大小写、空格都不能错
- weight 必须带符号(如 weight -20),否则 Keepalived 忽略该配置;主节点初始 priority 应比备节点高至少 50
确认 VIP 是否真实绑定到网卡
服务在跑、日志无报错,但业务不通,很可能是 VIP 根本没绑上去。
- 执行 ip addr show eth0(替换为配置中的 interface),查看虚拟 IP 是否出现在输出中
- 常见原因:interface 写成 ens33 而实际是 eth0、virtual_ipaddress 缩进错误或格式不规范(如写成 192.168.1.100/24 但未加掩码)、内核未启用 ip_nonlocal_bind(尤其在容器或云环境中)
- 临时测试可手动绑定:ip addr add 192.168.1.100/24 dev eth0,若能通则说明是 Keepalived 自身未触发绑定

















