如果您只有一分钟,请记住这张图:
flowchart TB
subgraph Normal["✅ 正常运行"]
Client1["客户端"] --> HAProxy1["HAProxy"]
HAProxy1 --> Primary1["🟢 Primary<br/>读写"]
Primary1 --> |流复制| Replica1["🔵 Replica<br/>只读"]
end
Normal --> |主库故障| Failover
subgraph Failover["⚡ 自动切换 (30秒内)"]
F1["1️⃣ Patroni 检测到主库心跳丢失"]
F2["2️⃣ Etcd 释放领导者锁,触发选举"]
F3["3️⃣ 数据最完整的从库提升为新主库"]
F4["4️⃣ HAProxy 自动路由到新主库"]
F1 --> F2 --> F3 --> F4
end
Failover --> Recovered
subgraph Recovered["✅ 服务恢复"]
Client2["客户端"] --> HAProxy2["HAProxy"]
HAProxy2 --> Primary2["🟢 新 Primary<br/>读写"]
Note["应用无需修改连接串<br/>无需重启"]
end
核心价值:硬件故障?自动切换。主库挂了?30 秒恢复。从库挂了?零感知切换。睡个好觉,让系统自己照顾自己。
本章内容
| 章节 | 说明 | 核心问题 |
|---|---|---|
| 高可用原理 | Patroni + Etcd + HAProxy 协同工作机制 | 故障自愈是如何实现的? |
| 故障切换 | 主库故障、从库故障时的检测与切换流程 | 故障发生后会怎样? |
| 利弊权衡 | RTO/RPO 参数调优与可用性/一致性的权衡 | 如何根据业务需求配置? |
高可用解决什么问题?
问题:单点故障
传统单机 PostgreSQL 面临一个残酷的现实:
flowchart LR
App["应用"] --> PG["PostgreSQL"]
PG --> Data["数据"]
PG --> |硬盘故障?<br/>内存错误?<br/>主板烧毁?<br/>机房断电?| Disaster
subgraph Disaster["💀 灾难后果"]
D1["服务完全中断"]
D2["数据可能丢失"]
D3["凌晨 3 点被叫醒"]
D4["手忙脚乱恢复"]
end
解决方案:高可用集群
Pigsty 的高可用方案让这一切自动化:
flowchart TB
App["应用"] --> HAProxy["HAProxy"]
HAProxy --> Primary["🟢 Primary"]
Primary --> |流复制| Replica1["🔵 Replica1"]
Primary --> |流复制| Replica2["🔵 Replica2"]
Primary --> |数据| D1["数据"]
Replica1 --> |副本| D2["数据副本"]
Replica2 --> |副本| D3["数据副本"]
Primary -. "Primary 故障?" .-> Failover["⚡ 自动切换<br/>30 秒内完成"]
Failover --> Replica1
Replica1 --> |提升为| NewPrimary["🟢 新 Primary"]
subgraph Result["✅ 结果"]
R1["服务短暂闪断后恢复"]
R2["数据安全(有副本)"]
R3["无需人工干预"]
R4["继续睡觉"]
end
高可用的价值
故障自愈
- RTO < 30s:主库故障后 30 秒内自动恢复服务
- RPO < 1MB:默认配置下最多丢失约 1MB 未同步数据(可配置为 0)
- 零人工干预:从检测到恢复全自动完成
滚动维护
- 无需停服:通过主动切换(Switchover)可在不停服情况下维护任意节点
- 升级便利:滚动升级 PostgreSQL、操作系统、硬件无需业务配合
- 最小窗口:单次切换对业务影响仅几秒闪断
资源利用
- 从库可用:从库承载只读查询,分担主库压力
- 读写分离:通过不同端口自动路由读写流量
- 弹性扩展:增加从库即可线性提升只读吞吐
运维友好
- 硬件故障不紧急:自动恢复后可以第二天再处理故障节点
- 监控完善:复制延迟、连接数、健康状态一目了然
- 操作简单:一条命令完成切换、扩容、缩容
核心指标
默认配置
| 指标 | 默认值 | 说明 |
|---|---|---|
| RTO(恢复时间目标) | ≈ 30s | 主库故障到新主库接管的时间 |
| RPO(恢复点目标) | < 1MB | 故障时可能丢失的最大数据量 |
| 从库故障 RTO | ≈ 0 | 只读请求立即路由到其他从库 |
| 从库故障 RPO | = 0 | 从库故障不丢失数据 |
可选配置
使用 crit.yml 关键业务模板,可确保:
| 指标 | 配置值 | 说明 |
|---|---|---|
| RPO | = 0 | 同步复制,零数据丢失 |
| 代价 | 延迟增加 | 写入需等待从库确认 |
配置策略对比
根据您的业务需求,选择合适的配置策略:
| 配置策略 | RTO | RPO | 适用场景 |
|---|---|---|---|
| 单机 + 什么也不做 | ❌ 无法恢复 | ❌ 数据全丢 | 绝不推荐 |
| 单机 + 定期备份 | ⚠️ 数小时 | ⚠️ 丢失数小时数据 | 开发测试 |
| 单机 + 备份 + WAL 归档 | ⚠️ 数小时 | ✅ 丢失约数十 MB | 非关键业务 |
| 主从 + 自动切换 | ✅ < 1 分钟 | ✅ 丢失约百 KB | 大多数生产环境 |
| 主从 + 同步复制 | ✅ < 1 分钟 | ✅ 零丢失 | 金融/关键业务 |
高可用的代价
任何技术选择都有代价,高可用也不例外:
资源成本
单机部署: 1 台服务器
高可用部署: 至少 3 台服务器(1 主 2 从 + ETCD)
资源消耗增加约 3 倍,但获得了:
✅ 99.999% 可用性
✅ 数据安全性
✅ 运维便利性
复杂度
- 基础设施依赖:需要部署 Etcd 集群(Pigsty 已自动处理)
- 学习成本:需要理解 Patroni、HAProxy 等组件
- 调试难度:分布式系统问题定位比单机复杂
性能开销
- 异步复制:几乎无开销
- 同步复制:写入延迟增加(等待从库确认)
高可用的局限性
高可用不是万能的,它无法解决以下问题:
逻辑错误
-- 这条命令会立即复制到所有从库!
DROP TABLE users;
-- 高可用无法帮你恢复,因为:
-- 主库执行 → 从库复制 → 所有节点都删除了
解决方案:使用 时间点恢复(PITR) 回退到误操作前
软件缺陷
应用 Bug 导致的数据污染会复制到所有从库。
解决方案:配合 延迟集群 提供回退窗口
机房级灾难
如果整个机房断电或网络中断,所有节点都不可用。
解决方案:跨机房/跨区域部署,或使用云厂商多可用区
生产验证
许多大型组织与核心机构已经在生产环境中长时间使用 Pigsty 高可用方案:
| 指标 | 数据 |
|---|---|
| 最大部署规模 | 25,000 CPU 核心,220+ PostgreSQL 实例 |
| 单实例最大规格 | 64 核 / 512GB 内存 / 3TB NVMe SSD |
| 运行时间 | 5 年以上持续运行 |
| 硬件故障次数 | 数十次(磁盘、内存、主板、电源) |
| 数据丢失 | 零 |
| 总体可用性 | > 99.999% |
快速配置
最小高可用集群
# pigsty.yml - 三节点高可用集群
pg-test:
hosts:
10.10.10.11: { pg_seq: 1, pg_role: primary }
10.10.10.12: { pg_seq: 2, pg_role: replica }
10.10.10.13: { pg_seq: 3, pg_role: replica }
vars:
pg_cluster: pg-test
# 一条命令部署
bin/pgsql-add pg-test
关键业务配置
# 启用同步复制,确保零数据丢失
pg-critical:
hosts:
10.10.10.21: { pg_seq: 1, pg_role: primary }
10.10.10.22: { pg_seq: 2, pg_role: replica }
10.10.10.23: { pg_seq: 3, pg_role: replica }
vars:
pg_cluster: pg-critical
pg_conf: crit.yml # 关键业务模板
pg_rpo: 0 # 零数据丢失
接下来
了解高可用的工作原理:
相关话题: