高可用原理
Patroni、Etcd、HAProxy 如何协同工作,实现 PostgreSQL 集群的故障自愈。
Pigsty 的高可用架构基于三个核心组件的协同工作:Patroni 负责管理 PostgreSQL 进程与故障切换,Etcd 提供分布式共识与领导者选举,HAProxy 负责流量路由与健康检查。
架构概览
┌─────────────────────────────────────────────────────────┐
│ Etcd 集群 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ etcd1 │◄──►│ etcd2 │◄──►│ etcd3 │ │
│ └────▲────┘ └────▲────┘ └────▲────┘ │
└────────┼──────────────┼──────────────┼─────────────────┘
│ │ │
┌────────────────────┼──────────────┼──────────────┼────────────────────┐
│ │ │ │ │
│ ┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐ │
│ │ Patroni │ │ Patroni │ │ Patroni │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ ┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐ │
│ │PostgreSQL │ │PostgreSQL │ │PostgreSQL │ │
│ │ Primary │ │ Replica │ │ Replica │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ 流式复制 (WAL) │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ HAProxy │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │Port 5433 │ │Port 5434 │ │Port 5436 │ ... │ │
│ │ │ Primary │ │ Replica │ │ Default │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────┘
PostgreSQL 集群
组件职责
PostgreSQL
PostgreSQL 是整个系统的核心,提供关系型数据库服务。
- 使用标准流复制(Streaming Replication)搭建物理从库
- 主库接受读写请求,从库接受只读请求
- 在多个节点上部署相同集群名的实例,自动形成主从复制拓扑
Patroni
Patroni 是高可用的控制平面,负责管理 PostgreSQL 进程的完整生命周期。
- 将 PostgreSQL 作为子进程启动和管理
- 监控 PostgreSQL 的健康状态
- 与 Etcd 交互进行领导者选举和配置存储
- 提供 REST API(默认端口 8008)供健康检查使用
- 执行自动故障转移(Failover)和主动切换(Switchover)
Etcd
Etcd 是分布式配置存储(DCS),为高可用提供共识基础。
- 存储集群的元数据和配置信息
- 提供分布式锁机制实现领导者选举
- 集群领导者持有租约,心跳续期
- 当领导者失联超时,触发新一轮选举
HAProxy
HAProxy 是流量入口,负责服务路由和负载均衡。
- 通过 Patroni REST API 进行健康检查
- 根据实例角色(Primary/Replica)分发流量
- 不同端口对应不同服务:5433(读写)、5434(只读)、5436(直连)
- 故障切换对应用透明,无需修改连接串
工作流程
正常运行时
- Patroni 定期向 Etcd 发送心跳,续期领导者租约
- Patroni 监控本地 PostgreSQL 健康状态
- Patroni 通过 REST API 对外暴露实例角色
- HAProxy 周期性检查 Patroni API,维护后端池
- 客户端流量通过 HAProxy 路由到正确的实例
从库故障时
- HAProxy 检测到从库 Patroni API 不可达
- HAProxy 将该从库从后端池中移除
- 只读流量自动路由到其他健康从库
- 如果所有从库都故障,只读流量回退到主库
- 影响:部分只读查询闪断,立即恢复
主库故障时
- 主库 Patroni 停止向 Etcd 发送心跳
- Etcd 租约过期(默认 10 秒),释放领导者锁
- 存活的从库 Patroni 竞争领导者锁
- 数据最完整的从库(LSN 最高)胜出
- 胜选从库提升为新主库,其他从库重新指向新主库
- HAProxy 检测到角色变化,更新路由
- 影响:写服务短暂不可用(15s ~ 30s)
关键参数
| 参数 | 默认值 | 说明 |
|---|---|---|
pg_rto |
30 |
恢复时间目标(秒),用于计算 Patroni TTL |
pg_rpo |
1048576 |
恢复点目标(字节),控制允许的数据丢失量 |
patroni_watchdog_mode |
off |
看门狗模式,可启用硬件隔离防止脑裂 |
pg_conf |
oltp.yml |
配置模板,crit.yml 启用同步复制 |
同步复制
默认配置使用异步复制,主库故障时可能丢失少量未复制的数据(通常 < 1MB)。
如果需要确保零数据丢失(RPO = 0),可以启用同步复制:
pg_conf: crit.yml # 使用关键业务模板
pg_rpo: 0 # 恢复点目标设为零
crit.yml 模板自动启用:
synchronous_mode: true:启用同步复制synchronous_commit: on:事务提交需等待从库确认- 至少一个同步从库确认后事务才算提交成功
代价:写入延迟增加,吞吐量下降,从库故障会影响主库写入。