Patroni + HAProxy + Keepalived + watchdog + ETCD PostgreSQL 高可用集群架构分析
一、背景与目标
1. 项目背景
A. 业务场景
PostgreSQL 作为主流开源关系型数据库,在企业核心业务系统中扮演着关键角色。传统单节点部署存在单点故障风险,主从复制方案在主节点故障时需要手动切换,影响业务连续性。
B. 痛点分析
- 单点故障:主节点宕机导致服务中断
- 手动切换:故障恢复需要人工介入,耗时长
- 脑裂风险:网络分区可能导致多主节点
- 数据一致性问题:主备切换时数据可能丢失
2. 设计目标
A. 功能目标
- 实现自动故障检测与切换
- 保障数据一致性和完整性
- 提供读写分离能力
B. 非功能目标
- 高可用性:99.99% 以上
- 故障切换时间:毫秒级
- 业务无感知:透明切换
- 防止脑裂:分布式共识保障
二、总体架构
1. 设计原则
- 分层架构:客户端应用层、负载均衡层、数据库集群层、分布式一致性层
- 自动化运维:故障自动检测、自动切换、自动恢复
- 防止脑裂:基于分布式共识的选举机制
- 读写分离:智能路由优化性能
2. 系统架构
graph TB
Client[客户端应用层] --> VIP[虚拟 IP 192.168.231.140]
VIP -->|VRRP 协议| Keep1[Keepalived Master]
VIP -->|VRRP 协议| Keep2[Keepalived Backup]
Keep1 --> HA1[HAProxy 主节点]
Keep2 --> HA2[HAProxy 备节点]
HA1 -->|读写分离| Patroni1[Patroni Leader]
HA1 -->|只读| Patroni2[Patroni Follower]
HA1 -->|只读| Patroni3[Patroni Follower]
HA2 --> Patroni1
HA2 --> Patroni2
HA2 --> Patroni3
Patroni1 --> PG1[(PostgreSQL 主节点)]
Patroni2 --> PG2[(PostgreSQL 备节点)]
Patroni3 --> PG3[(PostgreSQL 备节点)]
Patroni1 -.分布式共识.-> ETCD1[(ETCD 节点 1)]
Patroni2 -.分布式共识.-> ETCD2[(ETCD 节点 2)]
Patroni3 -.分布式共识.-> ETCD3[(ETCD 节点 3)]
WD1[Watchdog 监控] -.心跳检测.-> Patroni1
WD2[Watchdog 监控] -.心跳检测.-> Patroni2
WD3[Watchdog 监控] -.心跳检测.-> Patroni33. 组件说明
- 客户端应用层:业务系统通过统一 VIP 访问,对底层架构无感知
- 负载均衡层:HAProxy + Keepalived 实现智能路由和负载均衡层高可用
- 数据库集群层:PostgreSQL + Patroni 实现数据高可用和自动故障转移
- 分布式一致性层:ETCD 集群提供强一致性保障,防止脑裂
- 进程监控层:Watchdog 监控 Patroni 进程状态,异常时强制重启
三、负载均衡层设计
1. HAProxy 组件
A. 组件职责
HAProxy(High Availability Proxy)是开源高性能代理软件,在架构中负责:
- 接收客户端连接请求
- 根据 PostgreSQL 节点角色进行读写分离路由
- 执行健康检查,自动剔除故障节点
- 实现负载均衡,优化资源利用
B. 核心架构
graph LR
Client[客户端请求] --> Frontend[Frontend 前端处理]
Frontend --> LB[Load Balancer 负载均衡]
LB --> Backend[Backend 后端管理]
Backend --> HC[Health Checker 健康检查]
Backend --> CM[Connection Manager 连接管理]
Backend --> Server1[(PostgreSQL 主节点)]
Backend --> Server2[(PostgreSQL 备节点 1)]
Backend --> Server3[(PostgreSQL 备节点 2)]
HC -->|健康检查| Server1
HC -->|健康检查| Server2
HC -->|健康检查| Server3
CM --> SE[Statistics Engine 统计引擎]C. 请求处理流程
sequenceDiagram
participant C as 客户端
participant H as HAProxy
participant P as Patroni/PostgreSQL
C->>H: 1. 发起连接
H->>H: 2. Accept Connection
H->>H: 3. Parse Request
H->>H: 4. Route Request
H->>H: 5. Select Server(读写分离)
H->>P: 6. Connect to Server
P-->>H: 7. Connection Established
C->>H: 8. Proxy Traffic
H->>P: 9. Forward Request
P-->>H: 10. Response
H-->>C: 11. Process Response
H->>C: 12. Close ConnectionD. 健康检查配置
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
inter 3s # 健康检查间隔 3 秒
fall 3 # 连续 3 次失败标记为 down
rise 2 # 连续 2 次成功标记为 up
option pgsql-check # PostgreSQL 专用健康检查
timeout connect 5s # 连接超时 5 秒
timeout server 30s # 服务器响应超时 30 秒E. 负载均衡算法
- Round Robin:轮询算法,默认方式
- Least Connections:最少连接算法
- Source IP Hashing:源 IP 哈希算法
- URI Hashing:URI 哈希算法
F. 健康检查类型
- TCP Check:TCP 端口连通性检查
- HTTP Check:HTTP 请求和响应检查
- SSL Check:SSL 证书和连接检查
- PostgreSQL Check:PostgreSQL 数据库检查
2. Keepalived 组件
A. 组件职责
Keepalived 通过 VRRP 协议实现虚拟 IP 高可用,为 HAProxy 主备节点提供心跳检测与故障切换,确保负载均衡层无单点故障。
B. 核心架构
graph TB
VRRP[VRRP 模块] -->|心跳广播| Master[主节点 Priority 100]
VRRP -->|心跳广播| Backup[备节点 Priority 90]
Master -->|持有 VIP| VIP[虚拟 IP 192.168.231.140]
Backup -->|待机| VIP
HC[健康检查模块] -->|监控 HAProxy| Master
HC -->|监控 HAProxy| Backup
HC -->|优先级调整| VRRP
SE[脚本执行器] -->|chk_haproxy.sh| HC
NS[通知系统] -->|状态变化告警| VRRP
IPVS[IPVS 集成] -->|负载均衡| VRRPC. VRRP 状态转换
stateDiagram-v2
[*] --> INIT: 系统启动
INIT --> BACKUP: 初始化完成
BACKUP --> MASTER: 收到更高优先级广告<br/>或选举超时
MASTER --> BACKUP: 收到更高优先级广告
MASTER --> FAULT: 健康检查失败
BACKUP --> FAULT: 健康检查失败
FAULT --> BACKUP: 故障恢复D. 配置示例
vrrp_instance VI_1 {
state MASTER # 主节点 MASTER,备节点 BACKUP
interface eth0 # 网络接口
virtual_router_id 51 # 虚拟路由 ID
priority 100 # 主节点优先级 100,备节点 90
advert_int 1 # VRRP 心跳广播间隔 1 秒
authentication {
auth_type PASS
auth_pass 62f7f8e5
}
virtual_ipaddress {
192.168.231.140/24 # 虚拟 IP 地址
}
}
vrrp_script chk_haproxy {
script "/check/haproxy.sh"
interval 3 # 检查间隔 3 秒
timeout 2 # 超时时间 2 秒
rise 2 # 成功阈值 2 次
fall 3 # 失败阈值 3 次
weight -30 # 优先级调整权重
}E. 故障处理机制
- 主节点故障:自动选举新主节点,VIP 无缝转移
- 健康检查失败:优先级自动调整,触发状态切换
- 服务恢复:自动回到正常状态,重新参与选举
四、分布式一致性层设计
1. ETCD 组件
A. 组件职责
ETCD 是基于 Raft 协议的分布式键值存储,为 Patroni 集群提供强一致性的状态存储与共识服务:
- 记录数据库节点角色信息
- 存储 Leader 选举信息
- 维护集群配置数据
- 保障 Leader 选举唯一性,防止脑裂
B. 核心架构
graph TB
Client[Patroni 客户端] --> API[API Server]
API --> Raft[Raft 一致性模块]
Raft --> Log[日志存储]
Raft --> Snapshot[快照存储]
Raft --> WAL[WAL 预写日志]
Log --> Store[(键值存储)]
Snapshot --> Store
WAL --> Store
Raft -->|心跳广播| Node1[ETCD 节点 1]
Raft -->|心跳广播| Node2[ETCD 节点 2]
Raft -->|心跳广播| Node3[ETCD 节点 3]C. Raft 选举流程
sequenceDiagram
participant F1 as Follower 节点 1
participant F2 as Follower 节点 2
participant F3 as Follower 节点 3
participant L as Leader
Note over F1,F3: Step 1: Follower State<br/>等待 Leader 心跳
F3->>F3: Election Timeout 超时
Note over F1,F3: Step 2: Election Timeout<br/>触发选举
F3->>F3: 转换为 Candidate State
Note over F1,F3: Step 3: Candidate State<br/>增加任期,发起投票
F3->>F1: RequestVote (任期 N)
F3->>F2: RequestVote (任期 N)
Note over F1,F3: Step 4: Vote Collection<br/>收集投票
F1-->>F3: 投票同意
F2-->>F3: 投票同意
Note over F1,F3: Step 5: Leader Election<br/>获得多数票成为 Leader
F3->>F3: 成为 Leader
Note over F1,F3: Step 6: Leader State<br/>发送心跳维持权威
F3->>F1: AppendEntries 心跳
F3->>F2: AppendEntries 心跳D. 选举参数配置
--heartbeat-interval=100ms # Leader 心跳间隔
--election-timeout=1000ms # 选举超时时间
--min-election-timeout=1000ms # 最小选举超时
--max-election-timeout=2000ms # 最大选举超时
--initial-election-tick-advance=true # 初始选举优化五、进程监控层设计
1. Watchdog 组件
A. 组件职责
Watchdog 通过接收 Patroni 的定时心跳来监控其运行状态:
- 监控 Patroni 进程健康状态
- 检测进程假死或心跳超时
- 触发服务或系统重启
- 防止故障节点导致脑裂
B. 核心架构
graph TB
Patroni[Patroni 进程] -->|每 10 秒心跳| WD[Watchdog 监控器]
WD -->|心跳超时 30 秒| Systemd[Systemd 服务管理器]
Systemd -->|重启服务| Patroni
WD -->|最后手段| Kernel[Linux Kernel Watchdog]
Kernel -->|强制重启| SystemC. 配置示例
# Watchdog 配置
watchdog:
mode: automatic
safety_margin: 5 # 安全裕度 5 秒
interval: 10 # 心跳间隔 10 秒
timeout: 30 # 超时时间 30 秒
# Systemd 服务配置
[Service]
WatchdogSec=30s # 看门狗超时 30 秒
Restart=on-failure # 失败时重启
RestartSec=1s # 重启间隔 1 秒
StartLimitBurst=3 # 启动限制次数
StartLimitInterval=60s # 启动限制时间窗口D. 故障场景处理
- 脑裂问题:多个主节点同时存在
- 进程假死:Patroni 进程存在但无响应
- 网络分区:节点与 ETCD 集群隔离
- 资源耗尽:CPU、内存或磁盘资源不足
E. 恢复处理流程
graph TB
Start[故障检测] --> Check{心跳超时?}
Check -->|是| Alert[告警通知]
Check -->|否| Monitor[继续监控]
Alert --> Restart[服务重启]
Restart --> Success{恢复成功?}
Success -->|是| Verify[恢复验证]
Success -->|否| SystemReboot[系统重启]
SystemReboot --> Verify
Verify --> End[恢复完成]
Monitor --> StartF. 防止脑裂机制
- 心跳超时检测:30 秒内未收到心跳触发告警
- 自动重启机制:防止故障节点继续写入数据
- 集群状态验证:与 ETCD 集群状态对比
- 数据一致性检查:验证 WAL 日志位置
六、数据库集群层设计
1. Patroni 组件
A. 组件职责
Patroni 是 PostgreSQL 高可用架构的核心管家:
- 实现自动化的主备选举
- 执行故障检测与故障转移
- 实时监控数据库状态
- 维护集群配置一致性
- 协调主备节点的流复制同步
- 对接 HAProxy 实现流量智能路由
B. 核心架构
graph TB
EM[Election Manager 选举管理器] -->|状态转换| HM[Health Monitor 健康监控器]
HM -->|节点状态检测| PG[PostgreSQL 数据库]
EM -->|分布式共识| EC[ETCD Client]
EC -->|存储/读取状态| ETCD[(ETCD 集群)]
PG -->|角色信息| HM
HM -->|健康检查| EM
EM -->|REST API| API[REST API 接口]
API -->|状态查询| Monitor[监控系统]
API -->|手动干预| Admin[管理员]C. 选举状态流程
stateDiagram-v2
[*] --> INIT: 系统初始化
INIT --> FOLLOWER: 加入集群
FOLLOWER --> CANDIDATE: Leader 故障检测
CANDIDATE --> LEADER: 获得多数票
CANDIDATE --> FOLLOWER: 未获得多数票
LEADER --> DEMOTED: 主动降级或故障
DEMOTED --> FOLLOWER: 降级完成
LEADER --> FOLLOWER: 重新选举D. 选举流程详解
sequenceDiagram
participant F1 as Follower 节点 1
participant F2 as Follower 节点 2
participant F3 as Follower 节点 3
participant E as ETCD 集群
participant PG as PostgreSQL
Note over F1,F3: 故障检测
F1->>E: 检测 Leader 心跳超时
F2->>E: 检测 Leader 心跳超时
Note over F1,F3: 触发选举
F1->>F1: 转换为 CANDIDATE
F1->>E: 请求投票
F2->>E: 投票给 F1
Note over F1,F3: 收集选票
E-->>F1: 获得多数票
F1->>F1: 成为 Leader
Note over F1,F3: 提升 PostgreSQL
F1->>PG: 提升为主节点
PG-->>F1: 提升成功
Note over F1,F3: 通知集群
F1->>E: 更新集群状态
E-->>F2: 新 Leader 通知
E-->>F3: 新 Leader 通知E. 配置示例
dcs:
ttl: 30 # Leader 租约超时时间 30 秒
loop_wait: 10 # 心跳发送间隔 10 秒
retry_timeout: 10 # 重试超时时间 10 秒
maximum_lag_on_failover: 1048576 # 最大复制延迟 1MB
election:
retry_timeout: 10 # 选举重试超时 10 秒
maximum_retry_timeout: 30 # 最大选举重试超时 30 秒
retry_interval: 2 # 选举重试间隔 2 秒
priority: 100 # 节点优先级F. 防止脑裂机制
- ETCD 共识保障:使用分布式锁和租约机制
- 多数票原则:必须获得集群多数节点的支持
- 自动降级机制:故障节点自动降级避免数据不一致
七、技术选型
1. 技术栈对比
| 组件层次 | 技术选型 | 替代方案 | 选择理由 |
|---|---|---|---|
| 负载均衡 | HAProxy | Nginx、LVS | 性能优秀、PostgreSQL 专用健康检查 |
| VIP 高可用 | Keepalived | Heartbeat | 轻量级、配置简单、VRRP 标准 |
| 分布式共识 | ETCD | Consul、ZooKeeper | Raft 协议、强一致性、Go 语言高性能 |
| 数据库高可用 | Patroni | RePM、Pgpool | Python 开发、社区活跃、功能完善 |
| 进程监控 | Watchdog | Monit | 系统级保障、硬件级重启能力 |
2. 性能指标
- 故障检测时间:10-30 秒
- 故障切换时间:毫秒级
- 数据零丢失:基于同步复制
- 支持 5 万+ QPS
八、高可用机制分析
1. 多层级高可用保障
graph TB
subgraph 第一层
VIP[虚拟 IP] --> Keep[Keepalived 主备]
end
subgraph 第二层
Keep --> HA[HAProxy 负载均衡]
end
subgraph 第三层
HA --> Pat[Patroni 集群]
end
subgraph 第四层
Pat --> PG[PostgreSQL 主备]
end
subgraph 第五层
Pat --> ETCD[ETCD 共识]
WD[Watchdog] -.监控.-> Pat
end2. 故障场景处理
| 故障类型 | 检测方式 | 恢复机制 | 恢复时间 |
|---|---|---|---|
| HAProxy 主节点故障 | Keepalived 健康检查 | VIP 切换至备节点 | 3-5 秒 |
| PostgreSQL Leader 故障 | Patroni 健康监控 | 自动选举新 Leader | 20-30 秒 |
| Patroni 进程假死 | Watchdog 心跳检测 | 强制重启服务/系统 | 30-60 秒 |
| ETCD 节点故障 | Raft 协议 | 自动选举新 ETCD Leader | 1-2 秒 |
| 网络分区 | 多数票原则 | 隔离少数派节点 | 选举超时 |
九、监控告警
1. 监控指标
- HAProxy 层:连接数、队列长度、响应时间、后端节点状态
- Keepalived 层:VIP 状态、VRRP 状态、节点优先级
- Patroni 层:节点角色、复制延迟、选举状态
- PostgreSQL 层:连接数、TPS、锁等待、WAL 位置
- ETCD 层:集群健康、Leader 状态、提案延迟
- Watchdog 层:心跳状态、重启次数
2. 告警规则
- VIP 切换告警
- PostgreSQL 主备切换告警
- 复制延迟超阈值告警
- ETCD 集群成员变更告警
- Watchdog 触发重启告警