主备切换无法绝对无损,但通过nginx与keepalived协同优化(如arp刷新、内核参数、graceful shutdown、preempt_delay、健康检查等),可实现毫秒级平滑切换,确保用户请求不中断。

主备切换本身无法做到绝对“无损”,但通过合理配置 Nginx 和 Keepalived,可将连接中断控制在毫秒级,实现业务感知不到的平滑切换。关键不在“零丢包”,而在“不中断用户请求”——这依赖于 TCP 连接复用、健康检查精度、VRRP 抢占策略与内核参数协同优化。
确保 VIP 切换不触发连接重置
Keepalived 使用 VRRP 协议管理虚拟 IP(VIP),切换本质是 MAC 地址广播变更。若客户端缓存旧 ARP 表,可能短暂发包失败。解决方法:
- 在 keepalived.conf 的 vrrp_instance 块中启用 notify 脚本,在状态切换时主动刷新局域网 ARP 缓存(如调用
arping -U -I eth0 $VIP) - 主备节点均配置内核参数
net.ipv4.conf.all.arp_ignore = 1和net.ipv4.conf.all.arp_announce = 2,避免非 VIP 接口响应 ARP 请求 - 客户端侧建议开启 TCP keepalive(应用层心跳更佳),避免长连接因网络静默被中间设备断开
让 Nginx 真实退出前完成已有请求
Keepalived 检测到 Nginx 异常后会立即触发 VIP 迁移,但此时 Nginx worker 进程可能仍在处理请求。需确保 graceful shutdown:
- 监控脚本(如
chk_nginx.sh)不应仅检查进程是否存在,而应使用curl -f http://127.0.0.1/health或nginx -t && nginx -s reload验证服务可达性 - 主节点 Nginx 配置中设置
worker_shutdown_timeout 5s,让 worker 在收到 SIGQUIT 后最多等待 5 秒完成当前请求再退出 - Keepalived 的 weight 调整要配合 Nginx 状态:脚本返回非 0 时,
weight -20使优先级低于备机,但不立即抢占,留出缓冲窗口
避免脑裂与反复切换
网络分区或心跳丢失可能导致主备同时持有 VIP(脑裂),造成请求乱序或 502。必须加固:
- 禁用
preempt仅适用于单向故障恢复场景;生产环境建议主备都设preempt_delay 30,即备机升主后等待 30 秒再接管,确认主节点确实不可达 - 心跳检测间隔
advert_int设为 1,但搭配至少 3 次连续失败才判定故障(fail_count 3),避免瞬时抖动误切 - 主备
virtual_router_id必须相同,auth_pass大小写敏感且一致,否则 VRRP 报文被丢弃,形成假“双主”
客户端连接层的容错配合
服务端再稳定,客户端未重试也会感知失败。建议:
- HTTP 客户端启用连接池并设置合理超时:
connectTimeout=3s、readTimeout=10s、maxRetries=2 - DNS 解析不要直写 VIP,而应通过域名(如
api.example.com)指向 VIP,便于后续扩展 DNS 负载均衡 - 前端或网关层增加重试逻辑(如 5xx 错误自动重放 GET/HEAD 请求),对幂等接口尤其有效











