用Nginx做反向代理或者静态资源服务时,很多团队会遇到同一个问题:前面只有一台机器,这台机器一旦挂掉,所有请求都会失败。给Nginx前面再加负载均衡又显得过重,这时候Keepalived就是一个性价比很高的方案。它不需要额外增加机器,只用两台已有的Nginx服务器,通过虚拟IP漂移机制对外暴露一个统一的访问入口,主节点故障时备节点自动接管虚拟IP,客户端完全无感知。

一、虚拟IP漂移的底层原理:VRRP协议
Keepalived的核心功能建立在VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)之上。理解了VRRP,虚拟IP为什么会漂移、怎么漂移就都清楚了。
VRRP把多台物理服务器抽象成一个虚拟路由器,这个虚拟路由器拥有一个虚拟IP(VIP)和一个虚拟MAC地址。组内的服务器通过优先级竞选出Master角色,其余的作为Backup。Master负责响应针对虚拟IP的ARP请求,也就是说,外部客户端的请求实际上都发往Master节点。
维持主备关系靠的是心跳机制。Master会周期性地(默认每1秒)向组播地址224.0.0.18发送VRRP通告报文,报文里携带自己的优先级。Backup持续监听这个报文,如果连续三个周期(即约3秒,取决于advert_int和master_down_interval的计算)没有收到Master的通告,Backup就认为Master已经失效,于是触发新一轮选举,优先级最高的Backup升级为新的Master,并把虚拟IP绑定到自己的网卡上,同时发送免费ARP(Gratuitous ARP)刷新交换机的ARP缓存,让后续流量指向自己。整个切换过程通常在3到4秒内完成,对前端访问来说基本就是一次短暂的请求超时,之后自动恢复。
需要注意的是,虚拟IP并不是真实存在于某一台机器的物理网卡配置里,而是由Keepalived动态地作为ip别名添加到网卡上。你可以用ip addr命令观察:当前是Master的机器上会看到类似eth0:1或者直接挂在eth0下的VIP地址,而Backup机器上则看不到。VIP漂移的本质就是这个地址从旧Master的网卡上删除、在新Master的网卡上添加。
二、双机主备配置实战:两台Nginx实现高可用
假设我们有两台服务器:主节点192.168.10.11,备节点192.168.10.12,对外提供虚拟IP 192.168.10.100。两台机器都已经安装好Nginx并启动,下面通过Keepalived把它们组成高可用集群。
先在两台机器上安装Keepalived:
# CentOS/RHEL yum install -y keepalived # Ubuntu/Debian apt-get install -y keepalived
主节点(192.168.10.11)的配置文件,路径为/etc/keepalived/keepalived.conf:
! Configuration File for keepalived
global_defs {
router_id NGINX_MASTER # 节点标识,每台机器必须唯一
}
vrrp_instance VI_1 {
state MASTER # 初始角色,MASTER或BACKUP
interface eth0 # 绑定的物理网卡
virtual_router_id 51 # 虚拟路由ID,同组主备必须一致
priority 100 # 优先级,数值越大越有可能成为Master
advert_int 1 # 心跳通告间隔,单位秒
authentication {
auth_type PASS
auth_pass 1111 # 认证密码,同组主备必须一致
}
virtual_ipaddress {
192.168.10.100/24 dev eth0 label eth0:1 # 虚拟IP
}
}
备节点(192.168.10.12)的配置只有三处不同:router_id改成NGINX_BACKUP,state改成BACKUP,priority改成一个比100小的值,比如90。配置完成后分别启动服务:
systemctl start keepalived systemctl enable keepalived
验证方法很简单。在主节点执行ip addr show eth0,能看到192.168.10.100挂载在网卡上;此时用ping 192.168.10.100或访问Nginx是通的。接着在主节点上执行systemctl stop keepalived模拟故障,几秒后到备节点上再查IP地址,会发现VIP已经漂移过去,业务请求由备节点的Nginx继续处理。重新启动主节点的Keepalived后,由于默认是抢占模式,优先级更高的主节点会重新夺回VIP。
三、抢占模式与非抢占模式的选择
Keepalived默认工作在抢占模式下。只要Master恢复,因为它的优先级更高,就会立即发起抢占,把VIP重新抢回来。这种模式适合主节点机器性能明显更强、希望流量尽快回到主节点的场景。但抢占也有代价:每次主节点重启Keepalived、或者网络抖动导致心跳短暂中断,都会引起VIP来回切换,造成不必要的服务抖动。
非抢占模式可以避免这个问题。配置方法是把所有节点的state都设为BACKUP,并加上nopreempt指令。此时谁先启动谁就是Master,即使优先级更高的节点恢复上线,也不会主动抢占,只有当前Master真正故障时才发生切换。注意nopreempt只在state为BACKUP的实例中生效,这一点官方文档有明确说明,配错了不生效是常见的坑。
vrrp_instance VI_1 {
state BACKUP # 两台机器都配置为BACKUP
interface eth0
virtual_router_id 51
priority 100 # 非抢占模式下优先级仍需不同
advert_int 1
nopreempt # 开启非抢占模式
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.10.100/24
}
}
实际生产中,如果两台机器配置相当、业务没有主备之分,推荐非抢占模式,能显著减少VIP无意义漂移的次数。如果确实有明确的主节点(比如一新一旧两台机器),保留抢占模式并适当调大advert_int或调整故障检测参数,可以平衡切换速度和误判概率。
四、结合检测脚本实现Nginx进程级切换
只依赖VRRP心跳有一个明显的盲区:它只能检测Keepalived进程本身和服务器是否存活。如果Nginx进程挂了但服务器还在运行,心跳依然正常,VIP不会漂移,请求会全部打到一台Nginx已经死掉的机器上,高可用形同虚设。
解决这个问题的标准做法是使用vrrp_script配合track_script。通过一个自定义检测脚本周期性地检查Nginx状态,一旦检测失败就降低本节点的优先级,当优先级低于备节点时自动触发切换。
先编写检测脚本/etc/keepalived/check_nginx.sh:
#!/bin/bash
# 检测Nginx进程是否存活,不存在时尝试拉起,连续失败则退出非零
if ! pidof nginx > /dev/null; then
systemctl start nginx
sleep 2
if ! pidof nginx > /dev/null; then
exit 1
fi
fi
exit 0
记得赋予执行权限chmod +x /etc/keepalived/check_nginx.sh,然后在keepalived.conf中引用它:
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2 # 每2秒检测一次
weight -30 # 检测失败时优先级减30
fall 2 # 连续失败2次才判定失败
rise 2 # 连续成功2次才判定恢复
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
track_script {
chk_nginx # 引用上面定义的检测脚本
}
virtual_ipaddress {
192.168.10.100/24
}
}
配置的关键在于weight -30。主节点优先级100,检测失败后变成70,低于备节点的90,VIP立即漂移。Nginx恢复后优先级回到100,若处于抢占模式则会切回主节点。这样即使Nginx进程异常,系统也能在几秒内完成切换,实现了真正的应用层高可用。
五、脑裂问题的排查与预防
脑裂(Split Brain)是Keepalived部署中最需要警惕的故障。当主备之间的心跳链路中断,但双方都还活着时,备节点收不到通告会把自己升级为Master,主节点也认为自己是Master,于是两台机器同时持有VIP,双方不断发送免费ARP,导致客户端请求在两台机器之间来回跳,业务时通时断。
排查脑裂很简单:同时登录两台机器执行ip addr,如果看到VIP同时出现在两台机器上,就是发生了脑裂。常见原因包括交换机故障、防火墙拦截了VRRP协议(协议号112)、或服务器网卡驱动异常。
预防措施有几条。第一,确保防火墙放行VRRP报文,CentOS上可以执行firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent,iptables环境下放行协议号112即可。第二,尽量让主备机器连接不同的交换机,心跳走独立链路。第三,可以额外增加一条仲裁检测,比如在vrrp_script中ping网关地址,当本机连网关都ping不通时直接停止Keepalived进程,主动放弃Master角色,避免脑裂状态下继续抢流量。
vrrp_script chk_gateway {
script "ping -c 2 -W 1 192.168.10.1 > /dev/null"
interval 3
weight -60
fall 2
rise 2
}
通过优先级协商、故障检测脚本和脑裂防护三层机制配合,Keepalived加双Nginx的组合可以用极低的成本实现前端入口的高可用。这套方案在中小规模流量的场景下非常成熟稳定,配合LVS或后端服务健康检查,还能进一步扩展出更完整的负载均衡高可用架构。
Keepalived虚拟IP漂移高可用修改时间:2026-09-04 02:56:57