Nginx+Keepalived高可用集群搭建:双机热备配置与故障切换实战

高可用集群架构设计要点

Nginx+Keepalived是服务器运维中经典的负载均衡高可用方案。Keepalived基于VRRP协议实现虚拟IP漂移,Nginx负责七层负载均衡和请求分发。当主节点宕机时,备节点在秒级内接管虚拟IP,实现服务无感知切换。这套方案适用于Web服务、API网关、反向代理等场景,成本远低于商业F5设备。

架构拓扑:两台服务器运行Nginx+Keepalived,通过VRRP共享一个虚拟IP(VIP)。客户端请求到VIP,主节点处理请求并转发到后端Real Server。主节点故障时,VIP自动漂移到备节点,流量无缝切换。

环境准备与基础配置

测试环境使用两台CentOS 9服务器:

主节点 (MASTER):192.168.1.10
备节点 (BACKUP):192.168.1.11
虚拟IP (VIP):192.168.1.100
后端服务器:192.168.1.20, 192.168.1.21

两台机器安装Nginx和Keepalived:

# 安装EPEL源和必要组件
dnf install -y epel-release
dnf install -y nginx keepalived

# 开启IP转发(如果Nginx做四层代理需要)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

# 防火墙放行VRRP协议(关键步骤,很多故障出在这里)
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --reload

# 确保selinux不干扰
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

Nginx负载均衡配置

两台服务器的Nginx配置保持一致。编辑/etc/nginx/nginx.conf,配置反向代理和负载均衡:

http {
    upstream backend {
        # 后端Real Server,可加权轮询
        server 192.168.1.20:8080 weight=1 max_fails=3 fail_timeout=30s;
        server 192.168.1.21:8080 weight=1 max_fails=3 fail_timeout=30s;
        
        # 备用服务器,当所有主服务器都down时启用
        server 192.168.1.22:8080 backup;
    }

    server {
        listen 80;
        server_name 192.168.1.100;

        location / {
            proxy_pass http://backend;
            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 5s;
            proxy_read_timeout 60s;
            
            # 健康检查:后端返回502/503时自动剔除
            proxy_next_upstream error timeout http_502 http_503;
            proxy_next_upstream_tries 2;
        }

        # 健康检查端点,给Keepalived用
        location /health {
            access_log off;
            return 200 "ok\n";
            add_header Content-Type text/plain;
        }
    }
}

Nginx本身的健康检查是被动式的——只有请求失败才会触发剔除。主动健康检查需要Nginx Plus商业版或nginx_upstream_check_module第三方模块。免费方案是用Keepalived的脚本检测来间接实现。

Keepalived VRRP配置

主节点配置文件/etc/keepalived/keepalived.conf:

global_defs {
    router_id NGINX_MASTER
    vrrp_skip_check_adv_addr
    vrrp_strict
    vrrp_garp_interval 0
    vrrp_gna_interval 0
}

vrrp_script chk_nginx {
    script "/etc/keepalived/check_nginx.sh"
    interval 2
    weight -20
    fall 2
    rise 1
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass MyStr0ngP@ss
    }

    virtual_ipaddress {
        192.168.1.100/24
    }

    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和priority:

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90              # 比主节点低
    advert_int 1
    
    # 其余配置与master一致
    authentication {
        auth_type PASS
        auth_pass MyStr0ngP@ss
    }
    virtual_ipaddress {
        192.168.1.100/24
    }
    track_script {
        chk_nginx
    }
}

健康检查脚本与故障切换逻辑

Nginx存活检测脚本/etc/keepalived/check_nginx.sh:

#!/bin/bash
# 检测Nginx进程是否存在
if [ -f /run/nginx.pid ]; then
    pid=$(cat /run/nginx.pid)
    if kill -0 "$pid" 2>/dev/null; then
        exit 0
    fi
fi

# Nginx进程不存在,尝试重启
systemctl restart nginx
sleep 2

# 重启后再次检查
if [ -f /run/nginx.pid ]; then
    pid=$(cat /run/nginx.pid)
    if kill -0 "$pid" 2>/dev/null; then
        exit 0
    fi
fi

# 重启失败,返回非零,Keepalived会降低优先级触发切换
exit 1

切换通知脚本/etc/keepalived/notify.sh:

#!/bin/bash
STATE=$1
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
HOSTNAME=$(hostname)

case "$STATE" in
    master)
        logger "[$TIMESTAMP] $HOSTNAME 成为MASTER,VIP已接管"
        # 可选:发送告警通知到钉钉/飞书webhook
        curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
            -H "Content-Type: application/json" \
            -d "{"msgtype":"text","text":{"content":"Keepalived切换: $HOSTNAME 成为MASTER ($TIMESTAMP)"}}"
        ;;
    backup)
        logger "[$TIMESTAMP] $HOSTNAME 成为BACKUP"
        ;;
    fault)
        logger "[$TIMESTAMP] $HOSTNAME 进入FAULT状态"
        ;;
esac
# 赋予脚本执行权限
chmod +x /etc/keepalived/check_nginx.sh
chmod +x /etc/keepalived/notify.sh

# 启动服务
systemctl enable --now keepalived
systemctl restart nginx

故障排查与常见问题

问题1:VIP不漂移,主节点恢复后无法接管
检查两台机器是否在同一网段、virtual_router_id是否一致。用tcpdump抓VRRP报文确认心跳通信:

tcpdump -i eth0 vrrp -nn
# 应看到主节点每秒发送VRRP advertisement
# 如果没有任何报文,检查防火墙是否放行vrrp协议

问题2:脑裂(split-brain)
主备同时持有VIP,会导致MAC地址混乱。根因是主备之间网络不通,各自认为对方已宕机。排查方向:检查交换机是否启用了多播限制;尝试将VRRP改为单播模式:

vrrp_instance VI_1 {
    # ...
    unicast_src_ip 192.168.1.10    # 本机IP
    unicast_peer {
        192.168.1.11               # 对端IP
    }
}

问题3:Nginx正常但keepalived频繁切换
查看/var/log/messages中的keepalived日志。常见原因是check脚本超时返回或weight配置不当。weight值要保证主节点脚本失败后priority降到低于备节点——主节点100-20=80小于备节点90,就会触发切换。如果weight设得太小(比如-5),100-5=95仍大于90,就不会切换。

问题4:切换后服务短暂不可用
VRRP切换本身只需1-3秒,但客户端ARP缓存中VIP对应的MAC地址还没更新。解决办法是在notify_master脚本中发送免费ARP(gratuitous ARP):

# 在notify.sh的master分支中添加
arping -I eth0 -c 5 -s 192.168.1.100 192.168.1.1

安全加固与生产环境建议

Keepalived的auth_pass默认明文传输,在生产环境中应配合网络隔离。VRRP通信局限在内网,不要暴露在公网。

服务器安全加固方面,限制SSH访问源IP,禁用密码登录只允许密钥认证。定期更新系统补丁,配置fail2ban防止暴力破解。Nginx层面隐藏版本号(server_tokens off),限制请求体大小和速率防止CC攻击。

监控方面,通过Prometheus + keepalived_exporter采集VRRP状态指标,设置告警规则:当某个节点持续处于BACKUP超过预期时间,或发生非计划性切换时立即告警。算力资源规划上,备节点配置不应低于主节点,确保接管后能承载相同流量。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/nginxkeepalived-gao-ke-yong-ji-qun-da-jian-shuang-ji-re-bei/

(0)
小编小编
上一篇 16小时前
下一篇 16小时前

相关推荐