Nginx反向代理高可用集群搭建:Keepalived+Nginx双机热备配置实战

服务器高可用架构中,Nginx作为反向代理承担流量入口职责,单点故障会导致整个后端服务不可用。Keepalived通过VRRP协议实现虚拟IP(VIP)在多台Nginx节点间漂移,当主节点宕机时,备节点在秒级接管VIP,实现流量无缝切换。本文记录一套双机热备Nginx集群的完整搭建过程,涵盖安装、配置、健康检查、故障切换验证和日志排查。

VRRP协议原理与双机热备架构设计

VRRP(Virtual Router Redundancy Protocol)将多台物理服务器虚拟为一个逻辑路由器组,组内选举一个Master节点持有VIP,其余为Backup节点。Master周期性发送VRRP通告包,Backup节点在约定时间内未收到通告即认为Master宕机,按优先级选举新Master并接管VIP。整个切换过程对客户端透明,因为VIP地址不变。

双机热备架构:两台Nginx服务器分别配置为VRRP Master和Backup,共享一个VIP对外提供服务。Nginx通过upstream模块将请求分发到后端应用服务器集群。Keepalived不仅管理VIP漂移,还通过vrrp_script模块持续检测Nginx进程存活状态,一旦检测到Nginx进程退出,主动降低自身优先级触发VIP切换。

Keepalived安装与环境准备

以CentOS Stream 9为例,通过EPEL仓库安装Keepalived:

dnf install -y epel-release
dnf install -y keepalived nginx psmisc
keepalived -v
nginx -v

# 开放VRRP协议端口(IP协议号112)
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
firewall-cmd --reload

网络规划:主节点IP 192.168.10.11,备节点IP 192.168.10.12,VIP 192.168.10.100,后端应用服务器 192.168.20.21-23。两台Nginx服务器的配置必须保持一致,可通过rsync+inotify实现配置文件自动同步。

Keepalived核心配置文件详解

主节点(192.168.10.11)的/etc/keepalived/keepalived.conf

global_defs {
    router_id NGINX_MASTER
    enable_script_security
    script_user root
}

vrrp_script check_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 K8jN2mPq
    }

    virtual_ipaddress {
        192.168.10.100/24 dev eth0
    }

    track_script {
        check_nginx
    }

    notify_master "/etc/keepalived/notify.sh master"
    notify_backup "/etc/keepalived/notify.sh backup"
    notify_fault  "/etc/keepalived/notify.sh fault"
}

备节点配置差异:router_id改为NGINX_BACKUPstate改为BACKUPpriority设为90。其余配置完全一致。

关键参数说明:priority 100为主节点优先级。weight -20表示健康检查脚本失败时,优先级降低20点,从100变为80,低于备节点的90,触发VIP漂移。fall 2表示连续2次检查失败才判定为故障。advert_int 1为VRRP通告间隔1秒,故障检测窗口约为2-3秒。

Nginx健康检查脚本编写

/etc/keepalived/check_nginx.sh脚本检测Nginx进程是否存活:

#!/bin/bash
NGINX_PID=$(pidof nginx)

if [ -z "$NGINX_PID" ]; then
    systemctl restart nginx
    sleep 2
    NGINX_PID=$(pidof nginx)
    if [ -z "$NGINX_PID" ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Nginx is DOWN" >> /var/log/keepalived_nginx.log
        exit 1
    fi
fi
exit 0

赋予执行权限:chmod +x /etc/keepalived/check_nginx.shenable_script_securityscript_user root确保脚本以root身份运行。

Nginx反向代理与upstream负载均衡配置

user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 16384;
    use epoll;
    multi_accept on;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    'rt=$request_time uct=$upstream_connect_time';

    access_log /var/log/nginx/access.log main buffer=32k flush=5s;
    error_log  /var/log/nginx/error.log warn;

    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    keepalive_requests 1000;

    gzip on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml;

    upstream backend_app {
        least_conn;
        server 192.168.20.21:8080 weight=5 max_fails=3 fail_timeout=30s;
        server 192.168.20.22:8080 weight=5 max_fails=3 fail_timeout=30s;
        server 192.168.20.23:8080 weight=3 max_fails=3 fail_timeout=30s;
        server 192.168.20.24:8080 backup;
        keepalive 32;
    }

    server {
        listen 80;
        server_name _;

        location /health {
            access_log off;
            return 200 "ok\n";
            add_header Content-Type text/plain;
        }

        location / {
            proxy_pass http://backend_app;
            proxy_http_version 1.1;
            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_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Connection "";
            proxy_connect_timeout 5s;
            proxy_send_timeout 30s;
            proxy_read_timeout 30s;
            proxy_next_upstream error timeout invalid_header http_502 http_503;
            proxy_next_upstream_tries 3;
            proxy_next_upstream_timeout 10s;
        }

        location /ws {
            proxy_pass http://backend_app;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_read_timeout 3600s;
        }
    }
}

least_conn策略将请求分发到当前连接数最少的后端服务器。max_fails 3 fail_timeout=30s表示30秒内失败3次的服务器被标记为不可用。proxy_next_upstream配置了当后端返回502/503或超时时,自动重试下一台服务器。

故障切换验证与日志排查

# 主节点启动
systemctl enable keepalived nginx
systemctl start nginx
systemctl start keepalived

# 验证VIP绑定在主节点
ip addr show eth0 | grep 192.168.10.100
# 预期输出: inet 192.168.10.100/24 scope global secondary eth0

# 备节点启动(不应持有VIP)
ip addr show eth0 | grep 192.168.10.100
# 预期无输出

# 模拟主节点Nginx故障
killall nginx
# 等待2-3秒

# 主节点日志: VRRP_Instance(VI_1) Entering FAULT STATE
# 备节点日志: VRRP_Instance(VI_1) Entering MASTER STATE

# 在备节点验证VIP已漂移
ip addr show eth0 | grep 192.168.10.100
# 预期输出: inet 192.168.10.100/24 scope global secondary eth0

脑裂问题诊断与防御方案

脑裂(Split-Brain)是双机热备最危险的故障模式:主备节点间的VRRP通告因网络分区中断,双方都认为对方故障,各自提升为Master并绑定VIP。诊断方法:检查两台服务器是否同时持有VIP。

防御方案:通过独立心跳链路和fencing机制。在两台Nginx服务器之间增加一条直连网线作为VRRP专用心跳通道:

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    lvs_sync_daemon_interface eth1
    virtual_router_id 51
    priority 100
    advert_int 1
    preempt_delay 10
    garp_master_delay 5
    garp_master_repeat 3

    authentication {
        auth_type PASS
        auth_pass K8jN2mPq
    }

    virtual_ipaddress {
        192.168.10.100/24 dev eth0
    }

    track_script { check_nginx }
    track_interface { eth0 eth1 }
}

track_interface监控网络接口状态,当eth0或eth1 down时触发优先级调整。preempt_delay 10设置恢复后延迟10秒再抢占,避免频繁切换。

Keepalived notify脚本实现告警通知

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

case $STATE in
    master)  MSG="${DATE} [${HOSTNAME}] 切换为MASTER,接管VIP ${VIP}" ;;
    backup)  MSG="${DATE} [${HOSTNAME}] 切换为BACKUP,释放VIP ${VIP}" ;;
    fault)   MSG="${DATE} [${HOSTNAME}] 进入FAULT状态" ;;
    *)       MSG="${DATE} [${HOSTNAME}] 未知状态: ${STATE}" ;;
esac

echo "$MSG" >> /var/log/keepalived_notify.log

curl -s -X POST \
    "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY" \
    -H 'Content-Type: application/json' \
    -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"${MSG}\"}}"

完成以上配置后,故障切换时间可控制在3秒以内,满足大多数业务场景的连续性要求。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/nginx-fan-xiang-dai-li-gao-ke-yong-ji-qun-da-jian/

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

相关推荐