背景
单点故障是生产环境的头号杀手——一台 Nginx 挂了,整个网站就 502。
HA(High Availability) = 多台机器 + 故障自动切换,业内有两大经典方案:
| 方案 | 代表 | 适用 |
|---|
| LVS + Keepalived | 章文嵩博士 | 四层负载、性能极致 |
| HAProxy + Keepalived | Willy Tarreau | 四/七层、配置友好、社区活跃 |
| Nginx + Keepalived | 1.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 / ...)
|
故障切换流程:
- 主节点 Keepalived 心跳正常 → VIP 留在主节点
- 主节点 Nginx 挂了 →
nginx_check.sh 检测失败 - Keepalived 把自己的 priority 减 20
- 备节点 priority 100 > 主节点 80 → VIP 漂移到备节点
- 备节点 Nginx 接管服务(前提:备节点 Nginx 配置和数据一致)
一、HAProxy vs Nginx vs LVS
1.1 三者对比
| 维度 | LVS | HAProxy | Nginx |
|---|
| 工作层 | 四层(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 关键概念
| 概念 | 含义 |
|---|
| VRRP | Virtual Router Redundancy Protocol,虚拟路由冗余协议 |
| VIP | Virtual IP,对外服务的 IP(飘在主节点网卡上) |
| priority | 优先级(0-254),主高备低 |
| nopreempt | 不抢占模式(备升主后,原主恢复不再抢回) |
| advert_int | VRRP 通告间隔(秒),默认 1 |
| virtual_router_id | VRRP 实例 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
|
常见原因:
- virtual_router_id 不一致
- auth_pass 不一致
- 防火墙没放 VRRP 协议(云环境):
1
| iptables -I INPUT -p vrrp -j ACCEPT
|
- 组播在云环境被禁用 → 改 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 漂移"的经典方案:
- Keepalived 提供 VIP 漂移(VRRP 协议)
- Nginx 健康检查脚本触发 failover
nopreempt 模式避免来回切换- 云环境用 unicast(组播被禁用)
- 主备配置必须一致(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 增强:单播模式支持多 peervrrp_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 漂移由云厂商原生提供:
- AWS:Secondary IP + ENI(高可用虚拟 IP)
- 阿里云:HAVIP(高可用虚拟 IP)+ API
- Azure:Load 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
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)