
单点Nginx负载均衡器本身就有天然的故障隐患,如果某个服务进程崩溃或者某台服务器宕机了的话,那么所有的流量入口都会受到影响。为了解决这个问题,可以采用Keepalived来搭建一个双机热备系统,利用VRRP协议在各节点之间协商虚拟路由的状态,把虚拟IP地址(VIP)绑定到当前的主节点上。当主节点出现异常的时候,备用节点会在几秒钟之内完成对VIP的接管,从而对外提供透明的服务地址切换功能。
Nginx是七层负载均衡器,和Keepalived一起使用可以互相补充:Keepalived做IP层的高可用,Nginx做应用层的流量分配,二者合起来就是一个完整的、高可用的负载均衡集群。
环境规划
| 节点角色 | 主机名 | IP地址 | 说明 |
|---|---|---|---|
| Master | lb-node1 | 192.168.10.101 | 主负载均衡节点 |
| Backup | lb-node2 | 192.168.10.102 | 备负载均衡节点 |
| VIP | — | 192.168.10.100 | 虚拟IP,对外提供服务 |
| Real Server | rs-01 ~ rs-02 | 192.168.10.201~202 | 后端应用服务器 |
所有系统都使用CentOS 7.x和内核3.10+。
Keepalived安装与核心配置
两个节点都进行了安装:
yum install -y keepalived nginx
Master节点 /etc/keepalived/keepalived.conf 核心配置:
global_defs {
router_id LVS_DEVEL_01
script_user root
enable_script_security
}
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
timeout 1
fall 2
rise 1
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.10.100/24 dev eth0
}
track_script {
chk_nginx
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
备份节点和主节点的区别只有state BACKUP和priority 100两个参数不同,其他都相同。
Nginx健康检查脚本
VIP漂移需要能够正确地判断出Nginx的状态,因此要编写一个名为/etc/keepalived/check_nginx.sh的文件
#!/bin/bash
counter=$(ps -C nginx --no-heading | wc -l)
if [ "${counter}" = "0" ]; then
systemctl start nginx
sleep 2
counter=$(ps -C nginx --no-heading | wc -l)
if [ "${counter}" = "0" ]; then
systemctl stop keepalived
fi
fi
当发现没有运行着Nginx的时候就会去启动它,如果启动不成功的话就会把Keepalived关掉并且让VIP漂移到备用服务器上。
授予执行权
chmod +x /etc/keepalived/check_nginx.sh
chmod +x /etc/keepalived/notify.sh
Nginx负载均衡配置
在 /etc/nginx/nginx.conf 文件中设置 upstream 和反向代理配置:
upstream backend_pool {
least_conn;
server 192.168.10.201:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.10.202:8080 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name _;
location / {
proxy_pass http://backend_pool;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 3s;
proxy_read_timeout 10s;
}
}
least_conn 策略把请求分发给连接数最少的后端服务器,适用于长连接的情况;而 max_fails 和 fail_timeout 一起用来做被动的健康检测。
状态变更通知机制
当用户身份发生改变的时候,notify.sh 会发出警报或者把信息记录下来:
#!/bin/bash
case "$1" in
master)
echo "$(date '+%F %T') [INFO] Transitioned to MASTER state, VIP active" >> /var/log/keepalived/state.log
# 可扩展:调用webhook推送企业微信/钉钉告警
;;
backup)
echo "$(date '+%F %T') [INFO] Transitioned to BACKUP state, VIP released" >> /var/log/keepalived/state.log
;;
fault)
echo "$(date '+%F %T') [ERROR] Entered FAULT state" >> /var/log/keepalived/state.log
;;
esac
验证与故障演练
正常状态验证:
# 在Master节点确认VIP已绑定
ip addr show eth0 | grep 192.168.10.100
# 从客户端持续访问VIP
curl -I http://192.168.10.100
故障切换试验:
# 在Master节点手动终止Nginx
systemctl stop nginx
# 观察check脚本是否尝试拉起,拉起失败后Keepalived停止
# 在Backup节点验证VIP已漂移
ip addr show eth0 | grep 192.168.10.100
# 客户端curl请求应无感知中断(短暂超时后恢复)
**恢复测试:** 重启Master节点的Keepalived与Nginx后,由于priority更高,VIP将重新抢占回来。若需禁用抢占(适用于状态同步场景),在vrrp_instance中添加 nopreempt 参数。
关键参数调优建议
- advert_int:VRRP通告间隔,默认1秒。网络稳定环境可调至0.5秒加快故障检测,但会增加网络开销。
- vrrp_script interval:健康检查间隔,2秒为平衡点,过短增加系统负载,过长延长故障发现时间。
- preempt_delay:抢占延迟,防止网络抖动导致频繁切换。
- 单播模式:多播受网络限制时,配置
unicast_src_ip与unicast_peer改用单播通信。
常见问题排查
| 现象 | 原因 | 解决方式 |
|---|---|---|
| VIP未漂移 | 防火墙阻断VRRP协议 | 放行协议号112或关闭防火墙 |
| 脑裂(双VIP) | 节点间网络隔离 | 检查交换机端口、配置unicast |
| Nginx正常但VIP漂移 | check脚本返回非0 | 检查脚本权限与逻辑 |
| 切换后连接中断 | 未配置连接保持 | Nginx启用 proxy_http_version 1.1 与 proxy_set_header Connection "" |
总结
Keepalived和Nginx一起使用可以以很小的成本实现负载均衡层的高可用性,VRRP协议保证IP层面的快速故障转移,健康检查脚本把应用状态和集群决策联系起来,通知机制提供了可观测性。在实际的生产环境中要根据业务特点来调整检测频率、抢占策略以及后端的健康检查参数,在变更窗口进行故障演练来验证切换时间。该架构还可以扩展成LVS+Keepalived四层方案或者引入etcd来进行配置动态同步从而形成一个完整的流量治理闭环。