nopreempt可避免主节点恢复后立即抢占vip引发二次切换,需同时满足:所有节点state设为backup、显式配置nopreempt、禁用vrrp_strict;配合preempt_delay和track_script才能实现健康感知的平滑切换。

用 nopreempt 参数能有效避免主节点恢复后立即抢回 VIP 导致的二次切换,从而减少业务抖动。它的核心作用不是“不让主节点当主”,而是“不急着抢回来”,让当前服务节点稳住流量,特别适合对连接稳定性要求高的场景(比如长连接、SIP 通话、WebSocket 或数据库代理)。
必须满足的配置前提
启用 nopreempt 不是加一行就完事,以下三点缺一不可:
- 所有节点 state 必须设为 BACKUP:哪怕你心里认它是“主”,配置里也不能写 MASTER;VRRP 角色由 priority 决定,不是靠 state 标签
- 明确指定 nopreempt:只写在需要“不抢占”的节点上(通常是高优先级那台),低优先级节点可不写(默认不抢占也不影响)
- 禁用 vrrp_strict 模式:这个严格模式会校验 VRRP 报文合法性,与 nopreempt + BACKUP 组合冲突,导致 Keepalived 启动失败或日志报错
为什么光配 nopreempt 还不够?补一个 preempt_delay
nopreempt 让节点“彻底不抢”,但有时你希望它“稍等再抢”——比如主节点刚重启,Nginx 还没热起来、数据库连接池还没建好,这时抢 VIP 反而引发错误。这时候加 preempt_delay N(单位秒)更实用:
- 主节点恢复后,先等待 N 秒(例如 300 秒),期间持续检查自身健康状态(如通过 track_script)
- 若等待期内一切正常,才发起抢占;若中途失败,则放弃
- 这比纯 nopreempt 更灵活,兼顾了资源回收和业务平滑
配合健康检测,避免“假恢复”触发误切
nopreempt 只管 VIP 归属逻辑,不管服务本身是否真可用。如果主节点 Keepalived 进程起来了,但 Nginx 崩了,它仍会安静待命,VIP 留在备机不动——这是对的;但万一它“假装健康”,就会让 VIP 长期滞留故障节点。
所以一定要搭配 track_script:
- 写个简单脚本检查 Nginx 进程或端口(如
curl -s http://127.0.0.1/health | grep ok) - 在 vrrp_instance 中引用,并设置 weight(如
weight -20),让健康失败直接拉低 priority - 这样即使 nopreempt 开着,只要服务不健康,priority 掉到比备机还低,VIP 就自然留在备机
验证是否生效的快速方法
别只看日志,用命令直击关键状态:
-
ip a | grep "inet.*virtual":确认 VIP 当前在哪台机器上 -
systemctl stop keepalived && sleep 2 && systemctl start keepalived模拟主节点闪断,观察 VIP 是否真的没切回去 -
tail -f /var/log/messages | grep -i "transition\|master\|backup":盯住状态切换日志,确认没有 “Entering MASTER STATE” 类似记录










