61 - 高可用与集群

单台服务器总有单点故障(SPOF)风险——硬件损坏、内核崩溃、网络中断都可能导致服务不可用。高可用(High Availability, HA)通过冗余、故障检测和自动切换将服务可用性从 99% 提升到 99.9% 甚至 99.99%。本章从 Keepalived(VIP 热备)到 HAProxy(负载均衡高可用)到 Pacemaker(集群资源管理),构建生产级的服务高可用方案。


61.1 高可用核心概念

可用性的度量

等级SLA年宕机时间常见方案
两个 999%3.65 天单台服务器 + 定期备份
三个 999.9%8.76 小时主备切换(Keepalived/HAProxy)
四个 999.99%52.6 分钟集群 + 自动故障转移 + 跨机房
五个 999.999%5.26 分钟全球多活 + 自动扩缩

高可用的基石

冗余(Redundancy)
 ├── 数据冗余:RAID、主从复制、DRBD
 ├── 服务冗余:主备/多活服务器
 ├── 网络冗余:多网卡、多路径
 └── 机房冗余:跨地域部署

故障检测(Health Check)
 ├── 网络层:ICMP ping
 ├── 传输层:TCP 端口探测
 ├── 应用层:HTTP 健康检查端点
 └── 心跳:集群节点间 keep-alive 信号

故障转移(Failover)
 ├── VIP 漂移(VRRP → Keepalived)
 ├── DNS 切换
 ├── 负载均衡器重新路由
 └── 集群管理器(Pacemaker)

数据一致性(共享存储)
 ├── 网络存储:NFS、iSCSI、Ceph、DRBD
 ├── 数据库主从复制
 └── 分布式共识:etcd、Consul

61.2 Keepalived:VRRP 虚拟 IP 热备

VRRP(Virtual Router Redundancy Protocol)允许两台服务器共享一个虚拟 IP(VIP)。Master 持有 VIP,Backup 监控 Master 并在其故障时自动接管。

 Client
 │
 ▼
 ┌─────────────┐
 │ VIP │
 │ 192.168.1.100│
 └──┬──────┬───┘
 │ │
 ┌────▼──┐ ┌─▼─────┐
 │Master │ │Backup │
 │Nginx │ │Nginx │
 │.10 │ │.11 │
 └───────┘ └───────┘

安装 Keepalived

# Debian / Ubuntu
sudo apt install keepalived -y
 
# RHEL / Fedora
sudo dnf install keepalived -y
 
# Arch
sudo pacman -S keepalived

Master 配置

sudo vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
 state MASTER
 interface eth0
 virtual_router_id 51
 priority 100 # Master 优先级更高
 advert_int 1 # 心跳间隔(秒)

 authentication {
 auth_type PASS
 auth_pass s3cr3t_vrrp
 }

 virtual_ipaddress {
 192.168.1.100/24 dev eth0
 }

 # Nginx 健康检查
 track_script {
 chk_nginx
 }
}

# Nginx 存活检测脚本
vrrp_script chk_nginx {
 script "/usr/bin/killall -0 nginx"
 interval 2
 weight -2
}

Backup 配置

sudo vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
 state BACKUP
 interface eth0
 virtual_router_id 51
 priority 50 # 比 Master 低
 advert_int 1

 authentication {
 auth_type PASS
 auth_pass s3cr3t_vrrp
 }

 virtual_ipaddress {
 192.168.1.100/24 dev eth0
 }

 track_script {
 chk_nginx
 }
}

vrrp_script chk_nginx {
 script "/usr/bin/killall -0 nginx"
 interval 2
 weight -2
}

自定义健康检查脚本

sudo vim /usr/local/bin/chk_nginx.sh
#!/bin/bash
# 比 killall 更精确的健康检查
 
# 检查 nginx 进程是否运行
if ! pgrep -x nginx > /dev/null; then
 exit 1
fi
 
# 检查是否可以绑定端口(实质功能测试)
if ! curl -fsS -o /dev/null http://127.0.0.1/health; then
 exit 1
fi
 
exit 0
sudo chmod +x /usr/local/bin/chk_nginx.sh
 
# 在 keepalived.conf 中使用
# vrrp_script chk_nginx {
# script "/usr/local/bin/chk_nginx.sh"
# interval 3
# rise 2 # 连续成功 2 次认为恢复
# fall 3 # 连续失败 3 次认为故障
# }
sudo systemctl enable --now keepalived
 
# 验证
ip addr show eth0 | grep 192.168.1.100

测试故障切换

# 在 Master 上停止 Nginx
sudo systemctl stop nginx
 
# 数秒后在 Backup 上查看 VIP 是否漂移
ip addr show eth0 | grep 192.168.1.100
 
# 恢复 Master 上的 Nginx
sudo systemctl start nginx
# VIP 会回到 Master(如配置了 nopreempt 则留在 Backup)
 
# 查看 keepalived 日志
sudo journalctl -u keepalived -f

61.3 HAProxy:TCP/HTTP 负载均衡与高可用

HAProxy 是高性能 TCP/HTTP 负载均衡器,配合健康检查自动将请求从故障后端移除。

安装

sudo apt install haproxy -y # Debian/Ubuntu
sudo dnf install haproxy -y # RHEL/Fedora
sudo pacman -S haproxy # Arch

基础 HTTP 负载均衡

sudo vim /etc/haproxy/haproxy.cfg
global
 log /dev/log local0
 maxconn 4096
 user haproxy
 group haproxy
 daemon

defaults
 log global
 mode http
 option httplog
 option dontlognull
 retries 3
 timeout connect 5000ms
 timeout client 50000ms
 timeout server 50000ms

# 统计页面
listen stats
 bind *:8404
 stats enable
 stats uri /stats
 stats refresh 10s
 stats auth admin:changeme

# 前端:接收入站流量
frontend web_frontend
 bind *:80
 bind *:443 ssl crt /etc/haproxy/ssl/mysite.pem

 # 根据域名路由到不同后端
 acl is_api hdr(host) -i api.example.com
 acl is_app hdr(host) -i app.example.com

 use_backend api_servers if is_api
 default_backend app_servers

# 后端:API 服务器池
backend api_servers
 balance roundrobin
 option httpchk GET /health
 http-check expect status 200

 server api-01 192.168.1.10:3000 check inter 3s rise 2 fall 3
 server api-02 192.168.1.11:3000 check inter 3s rise 2 fall 3
 server api-03 192.168.1.12:3000 check inter 3s rise 2 fall 3

# 后端:应用服务器池
backend app_servers
 balance leastconn
 option httpchk GET /health

 server app-01 192.168.1.20:8080 check inter 2s
 server app-02 192.168.1.21:8080 check inter 2s
 server app-03 192.168.1.22:8080 check inter 2s backup # 备份

TCP 模式(任意协议)

# 适用于 MySQL、PostgreSQL、Redis、非 HTTP 协议
listen mysql_proxy
 bind *:3306
 mode tcp
 balance leastconn
 option tcp-check
 
 server db-01 192.168.1.20:3306 check port 3306 inter 3s
 server db-02 192.168.1.21:3306 check port 3306 inter 3s

HAProxy + Keepalived 高可用

将两台 HAProxy 配合 Keepalived 实现 HAProxy 自身的高可用:

 Client
 │
 ▼
 ┌─────────────┐
 │ VIP │
 │ 192.168.1.100│
 └──┬──────┬───┘
 │ │
 ┌────▼──┐ ┌─▼─────┐
 │HAProxy │ │HAProxy│
 │Master │ │Backup │
 │.10 │ │.11 │
 └───┬────┘ └───┬───┘
 │ │
 ┌───────┼──────────┼───────┐
 ▼ ▼ ▼ ▼
 [Web-01] [Web-02] [Web-03] [Web-04]

每台 HAProxy 节点上同时运行 Keepalived,提供 VIP 漂移。


61.4 Pacemaker + Corosync:集群资源管理器

当场景复杂到需要管理多个资源之间的依赖关系(如”先挂载共享存储,再启动数据库,最后启动应用”),Pacemaker 是生产级的集群资源管理器。

安装

# RHEL / Fedora
sudo dnf install pacemaker corosync pcs -y
 
# Debian / Ubuntu
sudo apt install pacemaker corosync pcs -y
 
# Arch
sudo pacman -S pacemaker corosync pcs

基本配置

# 所有节点设置 hacluster 密码
sudo passwd hacluster
 
# 启用 pcsd
sudo systemctl enable --now pcsd
 
# 在任一节点上认证集群节点
sudo pcs host auth node01 node02 -u hacluster -p <password>
 
# 创建集群
sudo pcs cluster setup mycluster node01 node02
 
# 启动集群
sudo pcs cluster start --all
sudo pcs cluster enable --all

管理资源

# 查看集群状态
sudo pcs status
 
# 创建浮动 IP 资源
sudo pcs resource create VIP ocf:heartbeat:IPaddr2 \
 ip=192.168.1.100 cidr_netmask=24 op monitor interval=10s
 
# 创建 Nginx 资源
sudo pcs resource create Nginx systemd:nginx \
 op monitor interval=10s
 
# 设置资源约束(Nginx 必须运行在 VIP 所在节点)
sudo pcs constraint colocation add Nginx with VIP INFINITY
sudo pcs constraint order VIP then Nginx
 
# 设置 STONITH 禁用(测试环境;生产必须配置)
sudo pcs property set stonith-enabled=false

常用 Pacemaker 资源类型

资源代理说明
浮动 IPocf:heartbeat:IPaddr2虚拟 IP
文件系统ocf:heartbeat:Filesystem挂载共享存储
systemd 服务systemd:<service>管理服务
LVMocf:heartbeat:LVM激活逻辑卷
DRBDocf:linbit:drbdDRBD 主备切换
MySQLocf:heartbeat:mysql管理 MySQL
Dockerocf:heartbeat:docker管理容器
空资源ocf:heartbeat:Dummy占位/测试

61.5 DRBD:网络 RAID1

DRBD(Distributed Replicated Block Device)将两台服务器的磁盘通过网络实时同步,像网络版 RAID1。

┌──────────────┐ ┌──────────────┐
│ Node 1 │ Network │ Node 2 │
│ /dev/drbd0 │◄═══════►│ /dev/drbd0 │
│ = Primary │ Sync │ = Secondary │
│ 可读写 │ │ 只读 │
└──────┬───────┘ └──────┬───────┘
 │ │
 /dev/sdb1 /dev/sdb1

安装与配置

# 两台服务器上
sudo apt install drbd-utils -y # Debian/Ubuntu
sudo dnf install drbd drbd-utils -y # RHEL(需 EPEL)
sudo pacman -S drbd-utils # Arch
 
# 分区(在两台服务器上)
sudo fdisk /dev/sdb
# 创建相同大小的分区 /dev/sdb1
 
# 配置 DRBD 资源
sudo vim /etc/drbd.d/r0.res
resource r0 {
 protocol C;
 device /dev/drbd0;
 disk /dev/sdb1;
 meta-disk internal;

 on node01 {
 address 192.168.1.10:7788;
 }
 on node02 {
 address 192.168.1.11:7788;
 }
}
# 初始化元数据(两台服务器)
sudo drbdadm create-md r0
 
# 启动
sudo drbdadm up r0
 
# 在 Primary 节点上初始化同步
sudo drbdadm primary --force r0
 
# 格式化并挂载
sudo mkfs.ext4 /dev/drbd0
sudo mount /dev/drbd0 /mnt/shared
 
# 查看同步状态
sudo drbdadm status
watch -n 1 cat /proc/drbd
 
# 手动故障切换
# 在 Primary 上:
sudo drbdadm secondary r0
# 在 Secondary 上:
sudo drbdadm primary r0

61.6 裂脑(Split-Brain)问题

什么是裂脑

当集群节点间的通信中断,两节点都认为自己是 Master 并写入数据——导致数据不一致。

初始状态: 通信中断: 裂脑:
Node1 (Primary) Node1 ─X─ Node2 Node1 认为自己是 Primary
Node2 (Secondary) Node2 也把自己升为 Primary
 两者同时写入 → 数据冲突

防止裂脑

  1. Quorum(法定票数):奇数节点,多数存活才能决策
  2. STONITH(Shoot The Other Node In The Head):物理上关闭故障节点
  3. Watchdog:硬件看门狗,故障时自动重启
# Pacemaker 中启用 STONITH(使用 IPMI 或 fence-agents)
sudo pcs stonith create fence-node01 fence_ipmilan \
 pcmk_host_list=node01 ipaddr=192.168.1.10 \
 login=admin passwd=password lanplus=1 action=reboot
 
# 启用 quorum
sudo pcs property set no-quorum-policy=freeze

61.7 实战:Keepalived + Nginx 高可用

拓扑

 Internet
 │
 ┌───────┴───────┐
 │ VIP: .100 │
 │ (Keepalived) │
 └───┬───────┬───┘
 │ │
 ┌────────▼─┐ ┌──▼────────┐
 │ Node 1 │ │ Node 2 │
 │ .10 │ │ .11 │
 │ Nginx │ │ Nginx │
 │ │ │ │
 │ Keepalived││ Keepalived│
 │ MASTER │ │ BACKUP │
 └──────────┘ └───────────┘
 │ │
 └───────┬───────┘
 │
 ┌───────▼───────┐
 │ Backend API │
 │ .20 .21 │
 └───────────────┘

完整部署脚本

#!/bin/bash
# deploy-nginx-ha.sh
set -euo pipefail
 
if [ $# -lt 2 ]; then
 echo "用法: $0 <master|backup> <vip>"
 exit 1
fi
 
ROLE=$1
VIP=$2
 
# 安装 Nginx + Keepalived
sudo apt update
sudo apt install -y nginx keepalived
 
# Nginx 配置(两台服务器相同)
sudo tee /etc/nginx/sites-available/default << 'NGINX'
server {
 listen 80;
 server_name _;
 
 location / {
 return 200 'OK from $hostname\n';
 add_header Content-Type text/plain;
 }
 
 location /health {
 return 200 'OK\n';
 add_header Content-Type text/plain;
 }
}
NGINX
 
sudo nginx -t && sudo systemctl restart nginx
 
# Keepalived 配置
PRIORITY=100
if [ "$ROLE" = "backup" ]; then
 PRIORITY=50
fi
 
sudo tee /etc/keepalived/keepalived.conf << KEEPALIVED
vrrp_script chk_nginx {
 script "/usr/bin/curl -fsS http://127.0.0.1/health"
 interval 2
 rise 2
 fall 3
}
 
vrrp_instance VI_1 {
 state $([ "$ROLE" = "master" ] && echo "MASTER" || echo "BACKUP")
 interface $(ip route get 1 | awk '{print $5; exit}')
 virtual_router_id 51
 priority $PRIORITY
 advert_int 1
 
 authentication {
 auth_type PASS
 auth_pass s3cr3t_kp
 }
 
 virtual_ipaddress {
 $VIP/24
 }
 
 track_script {
 chk_nginx
 }
}
KEEPALIVED
 
# 确保内核参数允许绑定非本地 IP
echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
 
sudo systemctl restart keepalived
sudo systemctl enable keepalived nginx
 
echo "部署完成。VIP: $VIP"
echo "角色: $ROLE (priority=$PRIORITY)"
ip addr show | grep $VIP || echo "当前未持有 VIP"
# 在 Node 1 (.10)
bash deploy-nginx-ha.sh master 192.168.1.100
 
# 在 Node 2 (.11)
bash deploy-nginx-ha.sh backup 192.168.1.100

测试高可用

# 1. 确认 VIP 在 Master 上
curl http://192.168.1.100
# OK from web-node-01
 
# 2. 停止 Master 的 Nginx
ssh node01 "sudo systemctl stop nginx"
 
# 3. 等待几秒,测试 VIP
curl http://192.168.1.100
# OK from web-node-02 ← 自动切换到 Backup
 
# 4. 查看 Backup 的日志
ssh node02 "sudo journalctl -u keepalived -f | grep -i 'enter master\|transition'"
 
# 5. 恢复 Master 的 Nginx
ssh node01 "sudo systemctl start nginx"
# 如果未设置 nopreempt,VIP 会回到 Master

61.8 云原生高可用

Kubernetes 自带 HA

在 Kubernetes 中,高可用由平台处理:

# Deployment:Pod 自动故障迁移
apiVersion: apps/v1
kind: Deployment
spec:
 replicas: 3
 selector:
 matchLabels:
 app: web
 # 节点故障时,Controller 在新节点上创建 Pod
 
# Service:自带负载均衡
apiVersion: v1
kind: Service
spec:
 type: LoadBalancer # 云平台提供 LB
 selector:
 app: web

云平台负载均衡器

AWS ALB/ELB、GCP Load Balancer、Azure Load Balancer 提供托管的高可用入口:

# AWS CLI 示例:基于目标组创建 LB
aws elbv2 create-target-group --name my-targets --protocol HTTP --port 80 --vpc-id vpc-xxx
aws elbv2 create-load-balancer --name my-alb --subnets subnet-xxx subnet-yyy

61.9 监控与测试

集群状态监控

# Keepalived 状态
journalctl -u keepalived -f
cat /var/log/messages | grep -i keepalived
 
# HAProxy 统计
curl http://localhost:8404/stats
# 浏览器访问 http://<haproxy-ip>:8404/stats
 
# Pacemaker 状态
pcs status
pcs status resources
pcs status xml | jq .
 
# DRBD 连接状态
drbdadm status
cat /proc/drbd

故障切换测试清单

# 1. 停止 Nginx 服务,检查 VIP 是否漂移
# 2. 断开网线,检查 VIP 是否漂移
# 3. 重启整台服务器,检查服务恢复时间
# 4. 模拟高负载,检查心跳是否超时
# 5. 在生产低峰期进行真实故障演练
 
# 针对性测试
sudo systemctl stop nginx # 服务级故障
sudo iptables -A INPUT -j DROP # 网络隔离模拟(临时测试)
# sudo iptables -D INPUT -j DROP # 恢复

61.10 常见方案选型

场景推荐方案
两台 Nginx 主备Keepalived + VRRP
多台 Web 服务器负载均衡HAProxy(或 Nginx upstream)
HTTP 服务高可用HAProxy + Keepalived
数据库高可用(MySQL)Master-Slave + Keepalived + 脚本切换
数据库高可用(PostgreSQL)Patroni + etcd(自动故障切换)
文件共享存储NFS(简单)/ DRBD(块级同步)/ Ceph(分布式)
应用集群资源管理Pacemaker + Corosync
容器化环境Kubernetes(自带 HA 机制)
云环境云负载均衡器 + 多可用区部署

61.11 本章总结

技术层次作用
Keepalived (VRRP)IP 层VIP 在主备间自动漂移
HAProxy传输/应用层负载均衡 + 后端健康检查
Pacemaker集群管理多资源依赖编排 + 故障恢复
Corosync消息层集群节点间通信 + 心跳
DRBD块设备网络 RAID1 存储同步
云 LB平台层托管负载均衡,免运维

负载均衡内容补充见 57-Nginx反向代理与负载均衡,监控 HA 状态见 60-监控系统(Prometheus+Grafana)