利弊权衡
概览
故障恢复时间目标(RTO)与 数据恢复点目标(RPO)是高可用集群设计时需要仔细进行利弊权衡的两个参数。
- RTO(Recovery Time Objective,恢复时间目标)定义了在主库发生故障时,系统恢复写入能力所需的最长时间。
- RPO(Recovery Point Objective,恢复点目标)定义了在主库发生故障时,允许丢失的最大数据量。
Pigsty 使用的 RTO 与 RPO 默认值满足绝大多数场景下的可靠性要求,您可以根据您的硬件水平,网络质量,业务需求进行调整。
过小的 RTO 将增大误报几率,过小的 RPO 将降低成功自动切换的概率。两者均需要付出性能作为代价。
故障切换时的不可用时长上限由 pg_rto 参数控制,Pigsty 提供四种预设模式:fast、norm(默认)、safe、wide,分别对应不同的网络条件。减小 RTO 可以加快故障恢复,但会增加误切风险。详情请参阅 RTO 利弊权衡 文档。
潜在数据丢失量的上限由 pg_rpo 参数控制,默认为 1MB,减小这个值可以降低故障切换时的数据损失上限,但也会增加故障时因为从库不够健康(落后太久)而拒绝自动切换的概率。
参数解释
pg_rto
恢复时间目标(RTO)模式,Pigsty 提供四种预设:fast(14s)、norm(21s,默认)、safe(43s)、wide(92s)。
减小 RTO 可以加快故障恢复速度,但会增加误切风险(网络抖动被误判为故障)。 您需要根据实际网络条件选择合适的模式,在 恢复速度 与 误切风险 之间做出权衡。 详情请参阅 RTO 利弊权衡 文档。
pg_rpo
以字节为单位的恢复点目标(RPO),默认值:1048576,即 1MiB,这意味着在故障转移期间最多可以容忍 1MiB 的数据丢失。
当主节点宕机并且所有副本都滞后时,你必须做出一个艰难的选择: 是马上提升一个从库成为新的主库,付出可接受的数据丢失代价(例如,少于 1MB),并尽快将系统恢复服务。 还是等待主库重新上线(可能永远不会)以避免任何数据丢失,或放弃自动故障切换,等人工介入作出最终决策。 您需要根据业务的需求偏好配置这个值,在 可用性 和 一致性 之间进行 利弊权衡。
此外,您始终可以通过启用同步提交(例如:使用 crit.yml 模板),通过牺牲集群一部分延迟/吞吐性能来强制确保 RPO = 0。
保护模式
关于 RPO (数据丢失)的利弊权衡,可以参考 Oracle Data Guard 的三种保护模式设计理念。
Oracle Data Guard 提供三种保护模式,PostgreSQL 也可以通过配置实现这三种经典的高可用切换策略。
最大性能(Maximum Performance)
- 默认模式,使用
crit.yml之外的 Patroni 配置模板,Patronisynchronous_mode: false,不启用同步复制 - 事务提交仅需本地 WAL 持久化,无需等待从库,从库故障对主库完全透明,不影响服务
- 主库故障时可能丢失尚未发送/接收的 WAL(通常 < 1MB,正常网络条件通常在 10ms/100ms,10KB/100KB 量级)
- 针对性能优化,适用于常规业务场景,容许在故障时损失少量数据。
最大可用性(Maximum Availability)
- Pigsty 使用
crit.yml模板,配置有synchronous_mode: true+synchronous_mode_strict: false - 正常情况下等待至少一个从库确认,实现零数据丢失。当 所有 同步从库故障时,自动降级为异步模式继续服务
- 兼顾数据安全与服务可用性,是生产环境核心业务的推荐配置
最大保护(Maximum Protection)
- Pigsty 使用
crit.yml模板,启用 Patronisynchronous_mode: true并进一步配置为严格同步模式。 - 配置
synchronous_mode_strict: true,当所有同步从库故障时,主库将拒绝写入以防止数据丢失 - 可以配置
synchronous_commit: 'remote_apply',确保读写一致性。 - 事务必须在至少一个从库持久化后才返回成功,可以指定指定同步从库列表,配置更多同步从库以提高容灾能力
- 适用于金融交易、医疗记录等对数据完整性要求极高的场景
| 维度 | 最大性能 | 最大可用性 | 最大保护 |
|---|---|---|---|
| 名称 | Maximum Performance | Maximum Availability | Maximum Protection |
| 复制方式 | 异步 | 同步 | 同步 |
| 数据丢失 | 可能丢失(复制延迟量) | 正常零丢失,降级少量丢失 | 零丢失 |
| 主库写延迟 | 最低 | 中等(+1 次网络往返) | 中等(+1 次网络往返) |
| 吞吐量 | 最高 | 较低 | 较低 |
| 从库故障影响 | 无影响 | 自动降级,继续服务 | 主库停写 |
| RPO | < 1MB | = 0(正常)/ < 1MB(降级) | = 0 |
| 适用场景 | 常规业务、性能优先 | 重要业务、安全优先 | 金融核心、安全合规第一 |
| Pigsty 配置 | 默认配置 | pg_conf: crit.yml |
pg_conf: crit.yml + 严格模式 |
三种模式的区别在于 Patroni 的两个核心参数:synchronous_mode 与 synchronous_mode_strict 如何配置
synchronous_mode:Patroni 是否启用同步复制,如果启用,再看synchronous_mode_strict是否启用严格同步模式。synchronous_mode_strict = false,默认配置,允许当从库故障时降级为异步模式,主库继续服务(最大可用性)synchronous_mode_strict = true,禁止降级,主库停止写入直到同步从库恢复(最大保护)
| 模式 | synchronous_mode |
synchronous_mode_strict |
从库故障行为 |
|---|---|---|---|
| 最大性能 | false |
- | 无影响 |
| 最大可用性 | true |
false |
自动降级为异步 |
| 最大保护 | true |
true |
主库拒绝写入 |
Pigsty 默认使用可用性优先模式,这意味着当主库故障时,它将尽快进行故障转移,尚未复制到从库的数据可能会丢失(常规万兆网络下,复制延迟在通常在几KB到100KB)。
如果您需要确保故障切换时不丢失任何数据,您可以使用 crit.yml 模板使用一致性优先模式,来确保在故障转移期间没有数据丢失,但这会牺牲一些性能(延迟/吞吐量)作为代价。
最大保护 模式需要额外配置 synchronous_mode_strict: true,在从库全部故障时会导致主库停止写入服务!请确保至少有 两个同步从库,或接受这一风险后再启用此模式。
故障切换时序
关于 RTO (故障恢复时长)的利弊权衡,可以通过下面的 Patroni 故障检测与切换时序图进行分析。
恢复时间目标(RTO) 由多个阶段组成:
gantt
title RTO 时间分解 (默认配置 pg_rto=30s)
dateFormat ss
axisFormat %S秒
section 故障检测
Patroni 检测/停止续租 :a1, 00, 10s
section 选举阶段
Etcd 租约过期 :a2, after a1, 2s
候选者竞选 (比较 LSN) :a3, after a2, 3s
section 提升阶段
执行 promote :a4, after a3, 3s
更新 Etcd 状态 :a5, after a4, 2s
section 流量切换
HAProxy 检测新主库 :a6, after a5, 5s
HAProxy 确认 (rise) :a7, after a6, 3s
服务恢复 :milestone, after a7, 0s
| 参数 | 影响 | 调优建议 |
|---|---|---|
pg_rto |
TTL/loop_wait/retry_timeout 的基准 | 网络稳定可减小到 15-20s |
ttl |
故障检测时间窗口 | = pg_rto |
loop_wait |
Patroni 检查间隔 | = pg_rto / 3 |
inter |
HAProxy 健康检查间隔 | 可减小到 1-2s |
fall |
故障判定次数 | 可减小到 2 |
rise |
恢复判定次数 | 可减小到 2 |
当主库发生故障时,系统经历以下阶段:
sequenceDiagram
autonumber
participant Primary as 🟢 Primary
participant Patroni_P as Patroni (Primary)
participant Etcd as 🟠 Etcd Cluster
participant Patroni_R as Patroni (Replica)
participant Replica as 🔵 Replica
participant HAProxy as HAProxy
Note over Primary: T=0s 主库故障发生
rect rgb(255, 235, 235)
Note right of Primary: 故障检测阶段 (0-10s)
Primary-x Patroni_P: 进程崩溃
Patroni_P--x Etcd: 停止续租
HAProxy--x Patroni_P: 健康检查失败
Etcd->>Etcd: 租约倒计时开始
end
rect rgb(255, 248, 225)
Note right of Etcd: 选举阶段 (10-20s)
Etcd->>Etcd: 租约过期,释放领导者锁
Patroni_R->>Etcd: 检查资格 (LSN, 复制延迟)
Etcd->>Patroni_R: 授予领导者锁
end
rect rgb(232, 245, 233)
Note right of Replica: 提升阶段 (20-30s)
Patroni_R->>Replica: 执行 PROMOTE
Replica-->>Replica: 提升为新主库
Patroni_R->>Etcd: 更新状态
HAProxy->>Patroni_R: 健康检查 /primary
Patroni_R-->>HAProxy: 200 OK
end
Note over HAProxy: T≈30s 服务恢复
HAProxy->>Replica: 路由写入流量到新主库
关键时序公式:
RTO ≈ TTL + Election_Time + Promote_Time + HAProxy_Detection
其中:
- TTL = pg_rto (默认 30s)
- Election_Time ≈ 1-2s
- Promote_Time ≈ 1-5s
- HAProxy_Detection = fall × inter + rise × fastinter ≈ 12s
实际 RTO 通常在 15-40s 之间,取决于:
- 网络延迟
- 从库 WAL 回放进度
- PostgreSQL 恢复速度