Featured image of post HAProxy + Keepalived 高可用实战:Nginx 主备双机 + VIP 漂移

HAProxy + Keepalived 高可用实战:Nginx 主备双机 + VIP 漂移

HAProxy 2.4 + Keepalived 2.2 安装、systemd 自启、主备双机配置、VRRP 虚拟 IP 漂移、nginx_check.sh 健康检查脚本、故障切换演练

背景

单点故障是生产环境的头号杀手——一台 Nginx 挂了,整个网站就 502。

HA(High Availability) = 多台机器 + 故障自动切换,业内有两大经典方案:

方案代表适用
LVS + Keepalived章文嵩博士四层负载、性能极致
HAProxy + KeepalivedWilly Tarreau四/七层、配置友好、社区活跃
Nginx + Keepalived1.x / plus七层、配置最简单

本篇方案:Nginx + Keepalived + HAProxy(可选用),经典"主备双机 + VIP 漂移"。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[客户端]  ──>  [VIP: 192.168.50.130]
                │  ARP 通告 / VRRP 协议
        ┌───────┴───────┐
        │               │
   [主节点 Master]   [备节点 Backup]
   Keepalived       Keepalived
   Nginx :80         Nginx :80 (standby)
   priority=100      priority=90
        └─> [后端真实服务器池] (tomcat / gunicorn / ...)

故障切换流程

  1. 主节点 Keepalived 心跳正常 → VIP 留在主节点
  2. 主节点 Nginx 挂了 → nginx_check.sh 检测失败
  3. Keepalived 把自己的 priority 减 20
  4. 备节点 priority 100 > 主节点 80 → VIP 漂移到备节点
  5. 备节点 Nginx 接管服务(前提:备节点 Nginx 配置和数据一致)

一、HAProxy vs Nginx vs LVS

1.1 三者对比

维度LVSHAProxyNginx
工作层四层(IP)四/七层七层(HTTP)
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
功能仅转发丰富(健康检查、会话保持、统计)反代、缓存、限流
配置复杂度复杂(需要 ipvsadm)中等简单
社区中国主导法国/欧洲主导俄罗斯主导
HA 角色DR 模式性能最强七层更智能最简单

选型建议

  • 追求性能(十万 QPS 以上):LVS
  • 追求灵活(健康检查细、会话保持复杂):HAProxy
  • 追求简单(七层反代、HTTP 处理):Nginx

1.2 为什么本篇选 Nginx + Keepalived

Nginx 已经是"事实标准"的反代,用 Nginx 做 HA 比 HAProxy 更省机器(HAProxy 当主、备各一台 + Nginx 后端,又多两层)。Keepalived 提供 VIP 漂移,简单可靠

如果业务量大(单 VIP 扛不住 5w+ QPS),应该做"LVS DR + 多 Nginx"或"HAProxy + 多 Nginx",不要在单 Nginx 上死磕


二、安装

2.1 Keepalived 2.2.x

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Ubuntu
apt show keepalived
sudo apt install keepalived -y

# CentOS
yum install keepalived -y

# 验证
keepalived -v
# Keepalived v2.2.4 (08/21,2021)

systemd 管理

1
2
3
systemctl enable keepalived
systemctl start keepalived
systemctl status keepalived

2.2 HAProxy 2.4.x(可选)

如果需要 HAProxy 做四层负载 + Nginx 后端:

1
2
3
4
5
6
7
# Ubuntu
apt show haproxy
sudo apt install haproxy -y

# 验证
haproxy -v
# HAProxy version 2.4.22-0ubuntu0.22.04.2 2023/08/14

systemd 管理

1
2
3
systemctl enable haproxy
systemctl start haproxy
systemctl status haproxy

卸载

1
sudo apt purge haproxy -y

三、HAProxy 配置(可选)

配置文件/etc/haproxy/haproxy.cfg

3.1 最小可用配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Mozilla Intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

3.2 反代后端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Web 负载
frontend http-in
    bind *:80
    default_backend web-pool

backend web-pool
    balance roundrobin
    option httpchk GET /
    server web1 10.0.1.10:8080 check
    server web2 10.0.1.11:8080 check
    server web3 10.0.1.12:8080 check

# 统计页面
listen stats
    bind *:9000
    stats enable
    stats uri /stats
    stats auth admin:yourpassword

热加载(不中断):

1
2
haproxy -c -f /etc/haproxy/haproxy.cfg   # 验证
systemctl reload haproxy                  # 重新加载

四、Keepalived 配置(Nginx 主备)

4.1 关键概念

概念含义
VRRPVirtual Router Redundancy Protocol,虚拟路由冗余协议
VIPVirtual IP,对外服务的 IP(飘在主节点网卡上)
priority优先级(0-254),主高备低
nopreempt不抢占模式(备升主后,原主恢复不再抢回)
advert_intVRRP 通告间隔(秒),默认 1
virtual_router_idVRRP 实例 ID(同组必须相同)
authentication简单密码认证(防止误抢)
unicast_src_ip / unicast_peer单播模式(云环境默认,组播被禁用)

4.2 主节点(Master)/etc/keepalived/keepalived.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
! Configuration File for keepalived
global_defs {
    # 标识本节点的字符串,通常为 hostname
    # hostnamectl set-hostname nginx-master1 设置
    router_id nginx-master1
}

# Nginx 健康检查脚本
vrrp_script chk_nginx {
    script "/etc/keepalived/nginx_check.sh"
    interval 2          # 每 2 秒检查一次
    weight -20          # 失败一次 priority -20
    fall 3              # 连续失败 3 次才算挂
    rise 2              # 连续成功 2 次才恢复
}

# 虚拟路由实例
vrrp_instance VI_1 {
    state MASTER         # 主节点
    interface eth0       # 绑 VIP 的网卡(云主机可能是 eth1 / ens5)
    virtual_router_id 51 # 虚拟路由 ID(0-255),同组必须一致
    mcast_src_ip 192.168.50.133  # 本机真实 IP
    priority 100         # 主节点优先级(0-254)
    nopreempt            # 不抢占(备升主后,原主恢复不再抢)
    advert_int 1         # 通告间隔 1 秒

    # 认证(两边必须一致)
    authentication {
        auth_type PASS
        auth_pass 1111
    }

    # 健康检查
    track_script {
        chk_nginx
    }

    # 虚拟 IP(对外服务的 IP)
    virtual_ipaddress {
        192.168.50.130/24 dev eth0
    }
}

4.3 备节点(Backup)/etc/keepalived/keepalived.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
! Configuration File for keepalived
global_defs {
    router_id nginx-backup1
}

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

vrrp_instance VI_1 {
    state BACKUP          # 备节点
    interface eth0
    virtual_router_id 51  # 必须与主一致
    mcast_src_ip 192.168.50.134  # 备机真实 IP
    priority 90           # 备节点优先级(< 主)
    nopreempt
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1111
    }

    track_script {
        chk_nginx
    }

    virtual_ipaddress {
        192.168.50.130/24 dev eth0
    }
}

4.4 健康检查脚本 /etc/keepalived/nginx_check.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash
# 检测 Nginx 是否存活,不存活就停止 keepalived,触发 VIP 漂移

A=$(ps -C nginx --no-heading | wc -l)
if [ "${A}" -eq 0 ]; then
    # 尝试启动 nginx
    systemctl start nginx
    sleep 2
    # 再查一次
    A=$(ps -C nginx --no-heading | wc -l)
    if [ "${A}" -eq 0 ]; then
        # 启动失败,停掉 keepalived,VIP 漂移到备
        systemctl stop keepalived
    fi
fi

权限与运行

1
chmod +x /etc/keepalived/nginx_check.sh

4.5 启动

1
2
systemctl enable --now keepalived
systemctl status keepalived

查看 VIP 状态(主节点应有 VIP,备节点没有):

1
2
3
ip addr show eth0
# 主节点:inet 192.168.50.130/24 ...(VIP 在)
# 备节点:没有 192.168.50.130

查看 VRRP 状态

1
2
3
tail -f /var/log/syslog | grep -i vrrp
# VRRP_Instance(VI_1) Transition to MASTER STATE
# VRRP_Instance(VI_1) Entering MASTER STATE

五、故障切换演练

5.1 模拟主节点 Nginx 挂掉

1
2
3
4
5
# 在主节点
systemctl stop nginx
# 等 6 秒(fall=3 × interval=2)
# Keepalived 检测到 nginx 挂了,stop keepalived
# VIP 漂移到备节点

观察

1
2
3
4
5
6
7
# 主节点
ip addr show eth0
# VIP 消失

# 备节点
ip addr show eth0
# VIP 出现 192.168.50.130

客户端视角:从浏览器访问 http://192.168.50.130整个过程大概 6-10 秒有 502 错误,然后恢复。

5.2 主节点恢复(nopreempt 模式)

1
2
3
4
# 在原主节点
systemctl start nginx
# 启动 nginx,但 keepalived 还没启动
# 此时备节点继续服务(因为 nopreempt)

nopreempt 的意义

  • 用 nopreempt → 原主恢复后会"抢回" VIP,两次切换造成额外中断
  • nopreempt → 原主恢复后保持 BACKUP,VIP 留在备只在下次主挂时才回切

生产建议用 nopreempt。避免"来回切换"的抖动。

5.3 强制回切(如果需要)

临时:手动在备节点 systemctl stop keepalived,VIP 漂回主。

永久:用 preempt_delay(Keepalived 1.3+):

1
2
3
4
5
6
vrrp_instance VI_1 {
    state BACKUP
    priority 90
    preempt_delay 300   # 备升主后,5 分钟内原主恢复不回切
    ...
}

六、单播模式(云环境必看)

传统 VRRP 用组播224.0.0.18),但云主机(阿里云、AWS、华为云)通常禁止组播必须改单播:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51

    # 关闭组播
    # mcast_src_ip 192.168.50.133  ← 注释掉

    # 开启单播
    unicast_src_ip 192.168.50.133   # 本机真实 IP
    unicast_peer {
        192.168.50.134              # 对端真实 IP
    }

    priority 100
    ...
}

两个节点都要配(主备互换 unicast_src_ip 和 unicast_peer)。


七、Nginx + Keepalived 完整架构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
                            [客户端]
                                
                                
                          [VIP 192.168.50.130]
                                
        ┌───────────────────────┴───────────────────────┐
                                                      
   [ Nginx]              [ Nginx]              [后端集群]
   10.0.1.10               10.0.1.11               10.0.1.20-30
   Keepalived MASTER       Keepalived BACKUP       Tomcat/...
   priority 100             priority 90
                               
   nginx -t / reload         nginx -t / reload
                               
   /etc/nginx/conf.d/        /etc/nginx/conf.d/     rsync 同步
                               
       [共享后端 pool]

主备配置一致(用 rsync/ansible 同步):

1
2
3
# 在主节点
rsync -avz /etc/nginx/ 10.0.1.11:/etc/nginx/
rsync -avz /var/www/ 10.0.1.11:/var/www/

自动化:用 lsyncd(inotify + rsync)实时同步,或用 etcd/consul 配置中心。


八、Keepalived 邮件告警(可选)

Keepalived 自带邮件提醒,需要 sendmail/postfix

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
global_defs {
    notification_email {
        admin@example.com
    }
    notification_email_from keepalived@example.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id nginx-master1
}

vrrp_instance VI_1 {
    state MASTER
    smtp_alert        # 启用邮件告警
    ...
}

建议用第三方监控代替(Zabbix/Prometheus),邮件告警延迟高、易被忽略。


九、常见问题

9.1 VIP 不漂移

症状:主 nginx 挂了,备节点 VIP 一直不来。

排查

1
2
3
4
5
6
7
# 看 keepalived 日志
journalctl -u keepalived -f
# 或
tail -f /var/log/syslog | grep -i keepalived

# 看 VRRP 通信
tcpdump -i eth0 vrrp

常见原因

  1. virtual_router_id 不一致
  2. auth_pass 不一致
  3. 防火墙没放 VRRP 协议(云环境):
    1
    
    iptables -I INPUT -p vrrp -j ACCEPT
    
  4. 组播在云环境被禁用 → 改 unicast

9.2 脑裂(split-brain)

症状:主备同时持有 VIP,客户端有时连到主有时连到备。

原因

  • 主备之间通信中断(如防火墙、心跳网络故障)
  • 两边都以为对方挂了

对策

  • 双心跳线:两条物理/逻辑链路
  • iptables 阻断:主检测到脑裂时自己 iptables drop VRRP 报文,主动让出 VIP
  • 云环境:用云厂商的 HAVIP(高可用虚拟 IP)+ API 切换

9.3 VIP 配置后 ping 不通

1
2
3
4
5
6
7
8
# 看 VIP 是不是在网卡上
ip addr show eth0

# 看本地能否 ping 通
ping 192.168.50.130

# 看路由
ip route get 192.168.50.130

云环境特殊:AWS/阿里云 HAVIP 需要显式启用 ARP 响应。

9.4 keepalived 启动失败

1
2
3
# 详细日志
keepalived -D -f /etc/keepalived/keepalived.conf
# 看具体错误

十、卸载

1
2
3
4
5
6
7
systemctl stop keepalived
systemctl disable keepalived
apt remove keepalived -y
rm -rf /etc/keepalived

# 清理 VIP
ip addr del 192.168.50.130/24 dev eth0

小结

HAProxy + Keepalived 是"主备双机 + VIP 漂移"的经典方案:

  1. Keepalived 提供 VIP 漂移(VRRP 协议)
  2. Nginx 健康检查脚本触发 failover
  3. nopreempt 模式避免来回切换
  4. 云环境用 unicast(组播被禁用)
  5. 主备配置必须一致(rsync/ansible 同步)

生产部署三原则

  • 必须双心跳线(防止脑裂)
  • 必须 rsync 配置(主备一致)
  • 必须 nopreempt(避免抖动)

替代方案

  • 云原生:ALB/NLB + 多 AZ
  • K8s:Service + Ingress Controller
  • 更激进:双活(active-active),两边同时服务

下一步

  • 上 K8s,用 K8s Service + Ingress 替代 VIP
  • Pacemaker + Corosync 做更复杂的 HA 集群
  • 商业方案:F5 BIG-IP、Citrix ADC

2024 视角:Keepalived 在云原生时代"角色变化"

2016 那篇是基于"自己买物理机 / 私有云"的 HA 方案。2024 视角下,Keepalived 角色已经变化——在云上变成"边缘 / 混合云"工具,K8s / 微服务已经走另一套方案。

一、Keepalived 2.2 → 2.3(2024 现状)

  • 2024 主流版本:Keepalived 2.2.7+(2023-12 起进入 2.3 系列开发)。
  • 新特性
    • vrrp_unicast_peer 增强:单播模式支持多 peer
    • vrrp_startup_delay:开机延迟(避免启动时误切换)
    • vrrp_priority_increment:动态调整 priority
    • Python bindings(实验性):动态控制 keepalived
1
2
3
4
# 2024 装
apt install keepalived
keepalived -v
# Keepalived v2.2.7 (10/18,2023)

二、云上的"VIP 漂移"由云厂商接管

  • 2016 那篇自建 VIP 在云上经常失效(云厂商禁止组播 / 不允许私设 IP)。
  • 2024 云上 VIP 漂移由云厂商原生提供:
    • AWSSecondary IP + ENI(高可用虚拟 IP)
    • 阿里云HAVIP(高可用虚拟 IP)+ API
    • AzureLoad Balancer + Floating IP
    • 华为云HA VIP(2023 起提供)
1
2
3
4
5
# AWS CLI 把 Secondary IP 漂到备机
aws ec2 assign-private-ip-addresses \
    --network-interface-id eni-xxx \
    --private-ip-addresses 10.0.1.100 \
    --allow-reassignment
  • 结论云上不需要 Keepalived——直接用云厂商的 HA 方案。
  • Keepalived 仍有价值的场景:
    • 私有数据中心(自建机房)
    • 边缘节点(IoT / 工厂)
    • 混合云(部分在云、部分本地)

三、K8s 时代的"VIP 替代"

  • 2016 那篇 HA 思路是"VIP 漂移到备机"。
  • K8s 时代Service + Endpoints + kube-proxy 自动做"虚拟 IP 漂移":
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# K8s Service(自动实现 VIP 漂移)
apiVersion: v1
kind: Service
metadata:
  name: nginx-ha
spec:
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP
# K8s 自动分配 VIP(如 10.96.100.50)
# kube-proxy iptables / ipvs 自动 load balance
  • 优势:无需 Keepalived、K8s 自动处理故障切换、漂移时间 < 1 秒。

四、HAProxy 2.4 → 3.0+ 的变化

  • HAProxy 3.0(2024-04 发布 LTS):
    • HTTP/3(QUIC) 完整支持
    • Runtime API 增强(动态改配置)
    • Threads 模型(多线程 LB)
    • 新的 nbthread / thread-group 指令
1
2
3
4
# HAProxy 3.0 启用多线程
global
    nbthread 4
    cpu-map auto:1-4 0-3
  • 2024 HAProxy 仍是四/七层 LB 主流,但 Envoy / APISIX 正在分食市场。

五、Envoy / APISIX 的"现代 VIP 替代"

  • Envoy(CNCF毕业项目,2024 仍是云原生服务网格标准代理):
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Envoy Listener(替代 VIP)
static_resources:
  listeners:
  - name: main
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 80
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        config:
          stat_prefix: ingress_http
          route_config:
            virtual_hosts:
            - name: backend
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: backend_cluster }
  • APISIX(国产 Apache 项目,2024 大量企业用):
    • 动态路由(不重启热更)
    • 多协议(HTTP/gRPC/WebSocket/MQTT)
    • 内置 Dashboard(可视化配置)

六、keepalived + HAProxy 的"现代双活"写法

  • 2016 那篇给的是主备(一主一备)。
  • 2024 趋势双活(两边同时服务)—— Keepalived 可以实现:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 主节点 keepalived.conf
vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    nopreempt
    
    # 两边都启用 nginx
    notify_master "/etc/keepalived/scripts/start_local_lb.sh"
    notify_backup "/etc/keepalived/scripts/keep_local_lb.sh"
}
  • 两边都跑 nginx / HAProxy,但通过 DNS 智能解析 + 全局负载均衡分配流量。

七、Keepalived 的"健康检查"增强

  • 2016 那篇给的 nginx_check.sh 是"脚本检测 nginx 进程"。
  • 2024 现代写法:用 vrrp_track + vrrp_script + HTTP 检查
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
vrrp_script chk_nginx {
    script "curl -sf http://127.0.0.1/health || exit 1"
    interval 2
    weight -20
    fall 3
    rise 2
    timeout 5
}

vrrp_script chk_disk {
    script "df -h / | awk 'NR==2 {print $5}' | grep -E '^[8-9][0-9]%' && exit 1"
    interval 30
    weight -10
}
  • track_script 多个 script 同时跟踪。

八、IPv6 VIP

  • 2024 趋势:IPv6 的 VIP 部署:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    
    virtual_ipaddress {
        192.168.50.130/24 dev eth0
        2001:db8::130/64 dev eth0
    }
}
  • IPv6 默认不依赖 ARP / 组播——使用 NDP(Neighbor Discovery Protocol)。

源文档os/linux/第三方tools/dev/高可用/高可用.md(HAProxy/Keepalived 安装、主备配置、nginx_check.sh)

使用 Hugo 构建
主题 StackJimmy 设计