61 - 高可用与集群
单台服务器总有单点故障(SPOF)风险——硬件损坏、内核崩溃、网络中断都可能导致服务不可用。高可用(High Availability, HA)通过冗余、故障检测和自动切换将服务可用性从 99% 提升到 99.9% 甚至 99.99%。本章从 Keepalived(VIP 热备)到 HAProxy(负载均衡高可用)到 Pacemaker(集群资源管理),构建生产级的服务高可用方案。
61.1 高可用核心概念
可用性的度量
| 等级 | SLA | 年宕机时间 | 常见方案 |
|---|---|---|---|
| 两个 9 | 99% | 3.65 天 | 单台服务器 + 定期备份 |
| 三个 9 | 99.9% | 8.76 小时 | 主备切换(Keepalived/HAProxy) |
| 四个 9 | 99.99% | 52.6 分钟 | 集群 + 自动故障转移 + 跨机房 |
| 五个 9 | 99.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 keepalivedMaster 配置
sudo vim /etc/keepalived/keepalived.confvrrp_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.confvrrp_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 0sudo 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 -f61.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.cfgglobal
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 3sHAProxy + 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 资源类型
| 资源 | 代理 | 说明 |
|---|---|---|
| 浮动 IP | ocf:heartbeat:IPaddr2 | 虚拟 IP |
| 文件系统 | ocf:heartbeat:Filesystem | 挂载共享存储 |
| systemd 服务 | systemd:<service> | 管理服务 |
| LVM | ocf:heartbeat:LVM | 激活逻辑卷 |
| DRBD | ocf:linbit:drbd | DRBD 主备切换 |
| MySQL | ocf:heartbeat:mysql | 管理 MySQL |
| Docker | ocf: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.resresource 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 r061.6 裂脑(Split-Brain)问题
什么是裂脑
当集群节点间的通信中断,两节点都认为自己是 Master 并写入数据——导致数据不一致。
初始状态: 通信中断: 裂脑:
Node1 (Primary) Node1 ─X─ Node2 Node1 认为自己是 Primary
Node2 (Secondary) Node2 也把自己升为 Primary
两者同时写入 → 数据冲突
防止裂脑
- Quorum(法定票数):奇数节点,多数存活才能决策
- STONITH(Shoot The Other Node In The Head):物理上关闭故障节点
- 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=freeze61.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 会回到 Master61.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-yyy61.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)。