Keepalived主备切换是否生效取决于监控脚本返回值是否严格为0(健康)或非0(异常),必须显式exit、手动验证返回值,并与weight配置协同生效,同时排除脚本名、换行符、权限等干扰项。

Keepalived 主备切换是否生效,核心取决于监控脚本的返回值是否被正确识别和响应。返回值不是“看起来像对”,而是必须严格符合 Keepalived 的判定逻辑——它只认 0(健康/成功) 和 非0(异常/失败) 这两个信号,其余任何中间状态、日志输出、echo 内容或静默执行,都不会触发权重变化或角色迁移。
脚本返回值必须显式且唯一
很多问题源于脚本末尾没有明确 exit 语句,导致实际退出码依赖上一条命令的结果,极易被干扰。例如:
- 用
curl -I http://localhost:80 | grep "200 OK"判断服务,但未加set -e或|| exit 1,即使匹配失败,脚本仍可能以 0 退出 - 脚本中调用了多个 redis 命令,但只在部分分支写了
exit 0或exit 1,其他路径默认返回上一命令的退出码,造成不确定性 - 使用
if [ $? -eq 0 ]; then ... fi后未补全 else 分支并 exit,遗漏路径会返回上层 shell 的默认状态
建议所有监控脚本末尾统一用 exit 0 或 exit 1 显式收尾,不依赖隐式行为。
手动验证返回值比看日志更直接
别等故障发生才查,日常就该用 root 或 keepalived 实际运行用户身份测试:
sudo -u keepalived /etc/keepalived/check_redis.sh-
echo $?—— 看输出是不是你预期的 0 或 1 - 再模拟异常:停掉 Redis,重复执行,确认返回值变为非0
如果返回值始终是 0,哪怕服务已挂,说明脚本逻辑没覆盖失败路径;如果始终是非0,可能是权限、路径、命令不存在等基础问题。
返回值要和 weight 配置协同生效
脚本返回 0 只代表“健康”,但能否影响 priority,还要看 weight 是否被正确加载并参与计算:
- vrrp_script 中 weight 必须带符号(如
weight -20或weight +10),否则 Keepalived 默认忽略 - track_script 必须在 vrrp_instance 块内正确定义,不能漏写或拼错名称
- 所有节点 state 建议统一设为
BACKUP,靠 priority + weight 动态升降,避免 MASTER 强制抢占引发脑裂
例如:主节点 priority 150,脚本健康时 weight +0,异常时 weight -30 → 实际 priority 变为 120,低于备节点的 130,从而触发切换。
常见干扰项必须提前排除
有些看似无关的细节,会直接让脚本“静默失败”:
-
脚本名含 keepalived 字样:grep 匹配会误计入自身进程,导致
ps | grep类判断永远为真(如 check_keepalived.sh) -
Windows 编辑器保存的脚本:行尾是
\r\n,Linux 执行时报/bin/bash^M: bad interpreter,实际根本没运行 -
缺少可执行权限:
chmod +x /path/to/script.sh不可省略 -
shebang 错误:脚本写
#!/bin/bash却用/bin/sh解释执行,某些语法(如==、数组)会报错










