这是本节的多页打印视图。
点击此处打印.
返回本页常规视图.
故障时序模型
详细分析三种经典故障检测/恢复路径下,最差,最优,平均 RTO 的计算逻辑与结果
在 Patroni 中,根据故障检测的机制,有三条典型的 RTO 计算路径,本节将分情况讨论。
| 检测机制 | 检测主体 | 检测信号 | 典型故障 | 主要来源 |
|---|
| 被动检测 | DCS (etcd) | leader key TTL 到期 | 网络分区,节点崩溃,Patroni 宕机 | ttl |
| 主动探测 | Patroni 领导者 | pg_isready 失败 | PG 进程崩溃 | priamry_start_timeout |
| 手动触发 | 运维人员 | patronictl switchover/failover | 主动切换命令,维护操作 | haproxy_up |
检测到故障之后,恢复过程的 RTO 还需要包括恢复策略的耗时,以及 HAProxy 健康检查的耗时。
1 - 被动故障检测
被动故障检测(节点宕机,网络分区)场景下的 RTO 时序分析
Pigsty 提供了四种 RTO 配置策略,下面是对三类故障场景下,不同 RTO 模式的最差,最优,平均 RTO 的计算逻辑与结果分析。
被动检测
节点宕机/网络分区场景(被动检测)RTO 对比
| 模式 | 最好 RTO | 平均 RTO | 最坏 RTO | TTL 占比 |
|---|
| fast | 17s | 22s | 29s | 80% |
| norm | 28s | 33s | 41s | 83% |
| safe | 53s | 63s | 78s | 87% |
| wide | 97s | 128s | 168s | 82% |
故障路径
RTO 计算公式:
RTO = TTL等待 + 从库检测 + 竞争锁 + promote + HAProxy_UP
= (ttl - loop_wait ~ ttl) + (0 ~ loop_wait) + 选举 + HAProxy_UP
RTO 构成分析
RTO = TTL等待 + loop_wait + 选举(~1s) + HAProxy_UP
\_____/ \______/
主要固定成本 可变成本
- 固定成本:TTL 等待是最大成本(占 80%~87%),这是被动检测的本质代价
- 可变成本:从库检测延迟(0 ~ loop_wait)
- HAProxy 延迟:仅计算
rise × fastinter(UP 检测),DOWN 检测与选举并行,不在关键路径
TTL 等待时间的精确计算
Patroni Leader 每 loop_wait 续约一次,将 TTL 重置为完整值。当节点宕机时:
续约周期示意图:
──────────────────────────────────────────────────────────────→ 时间
│ │ │
续约 续约 续约
TTL=ttl TTL=ttl TTL=ttl
│←── loop_wait ───→│
如果故障发生在 Δt 处(续约后 Δt 时间):
TTL 剩余 = ttl - Δt
由于 Δt ∈ [0, loop_wait)
所以 TTL 等待 ∈ (ttl - loop_wait, ttl]
与主动检测(PG 崩溃)的关键差异
| 对比项 | 主动检测(PG 崩溃) | 被动检测(节点宕机) |
|---|
| 主要控制参数 | primary_start_timeout | ttl |
| Patroni 状态 | 存活,主动处理 | 失效,无法响应 |
| 锁释放方式 | 主动释放 | 自然过期 |
| RTO 公式核心 | 2×loop_wait + primary_start_timeout | (ttl-loop_wait~ttl) + loop_wait |
fast 模式
参数: ttl=20, loop_wait=5, inter=1s, fastinter=500ms, rise=2, fall=2
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 15s | ttl - loop_wait = 20 - 5(故障恰好在续约前) |
| 3 | 从库检测到 Leader 锁过期 | 0s | 从库恰好在 HA loop 检查点 |
| 4 | 从库竞争 Leader 锁 | 0.1s | DCS 单次写操作 |
| 5 | 执行 pg_ctl promote | 0.5s | WAL 已同步,promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 1s | rise=2 × fastinter=500ms |
| 总计 | | 17s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 20s | 完整 ttl = 20(故障恰好在刚续约后) |
| 3 | 从库检测到 Leader 锁过期 | 5s | 从库 HA loop 恰好错过,等待下一轮 |
| 4 | 从库竞争 Leader 锁 | 0.5s | DCS 操作 + 网络延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × inter=1s(从 DOWN 状态开始) |
| 总计 | | 29s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 18s | ttl - loop_wait/2 = 20 - 2.5 |
| 3 | 从库检测到 Leader 锁过期 | 2.5s | loop_wait/2 |
| 4 | 从库竞争 Leader 锁 | 0.3s | DCS 操作平均延迟 |
| 5 | 执行 pg_ctl promote | 0.7s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 1s | rise=2 × fastinter |
| 总计 | | 22s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 节点宕机,停止续约 | 0s | 0s | 0s |
| 2 | 等待 TTL 过期 | 15s | 18s | 20s |
| 3 | 从库检测到 Leader 锁过期 | 0s | 2.5s | 5s |
| 4 | 从库竞争 Leader 锁 | 0.1s | 0.3s | 0.5s |
| 5 | 执行 pg_ctl promote | 0.5s | 0.7s | 1s |
| 6 | HAProxy 检测新主 UP | 1s | 1s | 2s |
| 总计 | 17s | 22s | 29s |
fast 模式下节点宕机场景 RTO 范围为 17s ~ 29s,平均约 22s。TTL=20s 是主要耗时(占 80%),由于 loop_wait=5s 的续约频率,实际 TTL 等待范围被压缩到 15~20s。此配置适合同机房低延迟环境,追求最快的被动故障恢复。
norm 模式
参数: ttl=30, loop_wait=5, inter=2s, fastinter=1s, rise=2, fall=3
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 25s | ttl - loop_wait = 30 - 5(故障恰好在续约前) |
| 3 | 从库检测到 Leader 锁过期 | 0s | 从库恰好在 HA loop 检查点 |
| 4 | 从库竞争 Leader 锁 | 0.1s | DCS 单次写操作 |
| 5 | 执行 pg_ctl promote | 0.5s | WAL 已同步,promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 28s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 30s | 完整 ttl = 30(故障恰好在刚续约后) |
| 3 | 从库检测到 Leader 锁过期 | 5s | 从库 HA loop 恰好错过,等待下一轮 |
| 4 | 从库竞争 Leader 锁 | 0.5s | DCS 操作 + 网络延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 4s | rise=2 × inter=2s(从 DOWN 状态开始) |
| 总计 | | 41s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 28s | ttl - loop_wait/2 = 30 - 2.5 |
| 3 | 从库检测到 Leader 锁过期 | 2.5s | loop_wait/2 |
| 4 | 从库竞争 Leader 锁 | 0.3s | DCS 操作平均延迟 |
| 5 | 执行 pg_ctl promote | 0.7s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 33s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 节点宕机,停止续约 | 0s | 0s | 0s |
| 2 | 等待 TTL 过期 | 25s | 28s | 30s |
| 3 | 从库检测到 Leader 锁过期 | 0s | 2.5s | 5s |
| 4 | 从库竞争 Leader 锁 | 0.1s | 0.3s | 0.5s |
| 5 | 执行 pg_ctl promote | 0.5s | 0.7s | 1s |
| 6 | HAProxy 检测新主 UP | 2s | 2s | 4s |
| 总计 | 28s | 33s | 41s |
norm 模式下节点宕机场景 RTO 范围为 28s ~ 41s,平均约 33s。TTL=30s 是主要耗时因素(占 83%)。这是生产环境的平衡选择,在故障恢复速度和集群稳定性之间取得折中。
safe 模式
参数: ttl=60, loop_wait=10, inter=3s, fastinter=1s, rise=2, fall=3
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 50s | ttl - loop_wait = 60 - 10(故障恰好在续约前) |
| 3 | 从库检测到 Leader 锁过期 | 0s | 从库恰好在 HA loop 检查点 |
| 4 | 从库竞争 Leader 锁 | 0.2s | DCS 单次写操作 |
| 5 | 执行 pg_ctl promote | 0.5s | WAL 已同步,promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 53s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 60s | 完整 ttl = 60(故障恰好在刚续约后) |
| 3 | 从库检测到 Leader 锁过期 | 10s | 从库 HA loop 恰好错过,等待下一轮 |
| 4 | 从库竞争 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 6s | rise=2 × inter=3s(从 DOWN 状态开始) |
| 总计 | | 78s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 55s | ttl - loop_wait/2 = 60 - 5 |
| 3 | 从库检测到 Leader 锁过期 | 5s | loop_wait/2 |
| 4 | 从库竞争 Leader 锁 | 0.5s | DCS 操作平均延迟 |
| 5 | 执行 pg_ctl promote | 0.7s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 63s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 节点宕机,停止续约 | 0s | 0s | 0s |
| 2 | 等待 TTL 过期 | 50s | 55s | 60s |
| 3 | 从库检测到 Leader 锁过期 | 0s | 5s | 10s |
| 4 | 从库竞争 Leader 锁 | 0.2s | 0.5s | 1s |
| 5 | 执行 pg_ctl promote | 0.5s | 0.7s | 1s |
| 6 | HAProxy 检测新主 UP | 2s | 2s | 6s |
| 总计 | 53s | 63s | 78s |
safe 模式下节点宕机场景 RTO 范围为 53s ~ 78s,平均约 63s。TTL=60s 提供了充足的容错窗口(占 87%),能有效避免短暂网络抖动导致的误判。此配置适合对稳定性要求极高、可容忍分钟级中断的场景。
wide 模式
参数: ttl=120, loop_wait=30, inter=5s, fastinter=2s, rise=3, fall=5
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 90s | ttl - loop_wait = 120 - 30(故障恰好在续约前) |
| 3 | 从库检测到 Leader 锁过期 | 0s | 从库恰好在 HA loop 检查点 |
| 4 | 从库竞争 Leader 锁 | 0.5s | DCS 单次写操作(广域网延迟) |
| 5 | 执行 pg_ctl promote | 0.5s | WAL 已同步,promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 6s | rise=3 × fastinter=2s |
| 总计 | | 97s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 120s | 完整 ttl = 120(故障恰好在刚续约后) |
| 3 | 从库检测到 Leader 锁过期 | 30s | 从库 HA loop 恰好错过,等待下一轮 |
| 4 | 从库竞争 Leader 锁 | 2s | DCS 操作 + 广域网延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 15s | rise=3 × inter=5s(从 DOWN 状态开始) |
| 总计 | | 168s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 节点宕机,停止续约 | 0s | Patroni + PG 同时失效 |
| 2 | 等待 TTL 过期 | 105s | ttl - loop_wait/2 = 120 - 15 |
| 3 | 从库检测到 Leader 锁过期 | 15s | loop_wait/2 |
| 4 | 从库竞争 Leader 锁 | 1s | DCS 操作平均延迟 |
| 5 | 执行 pg_ctl promote | 0.7s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 6s | rise=3 × fastinter=2s |
| 总计 | | 128s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 节点宕机,停止续约 | 0s | 0s | 0s |
| 2 | 等待 TTL 过期 | 90s | 105s | 120s |
| 3 | 从库检测到 Leader 锁过期 | 0s | 15s | 30s |
| 4 | 从库竞争 Leader 锁 | 0.5s | 1s | 2s |
| 5 | 执行 pg_ctl promote | 0.5s | 0.7s | 1s |
| 6 | HAProxy 检测新主 UP | 6s | 6s | 15s |
| 总计 | 97s | 128s | 168s |
wide 模式下节点宕机场景 RTO 范围为 97s ~ 168s(约 1.6~2.8 分钟),平均约 128s(约 2.1 分钟)。TTL=120s 和 loop_wait=30s 提供极强的容错能力(TTL 占 82%),适合广域网/跨数据中心部署。此配置优先保证不误判,代价是故障切换时间较长。
2 - 主动故障检测
主动故障检测(Patroni 存活,PG 宕机)场景下的 RTO 计算逻辑与结果分析
Pigsty 提供了四种 RTO 配置策略,下面是对三类故障场景下,不同 RTO 模式的最差,最优,平均 RTO 的计算逻辑与结果分析。
RTO 计算
主动检测
PG 崩溃场景(主动检测)RTO 对比
| 模式 | 最好 RTO | 平均 RTO | 最坏 RTO |
|---|
| fast | 7s | 12s | 19s |
| norm | 18s | 23s | 31s |
| safe | 63s | 73s | 88s |
| wide | 127s | 158s | 198s |
故障路径
注意:HAProxy 检测旧主 DOWN 与 Patroni 流程并行执行,在 promote 完成前早已完成,不计入 RTO。
RTO 计算公式:
RTO = loop_wait + primary_start_timeout + loop_wait + 选举 + HAProxy新主UP
= 2 × loop_wait + primary_start_timeout + 选举 + HAProxy新主UP
RTO 构成分析
RTO = 2 × loop_wait + primary_start_timeout + 选举(~1s) + HAProxy新主UP
\_________/ \__________________/
可变成本 固定成本
- 固定成本:
primary_start_timeout 是最大的固定成本,占 RTO 的 27%~96% - 可变成本:主要来自
2 × loop_wait(主库检测 + 从库检测),最坏情况两者都是满值 - HAProxy 延迟:仅计算
rise × fastinter(新主上线检测),约 1~15s - HAProxy 旧主 DOWN:与 Patroni 流程并行执行,在 promote 完成前早已完成,不计入 RTO
与被动检测(节点宕机/网络分区)的差异:节点宕机时 Patroni 也死了,无法主动释放锁,只能等 TTL 过期被动触发。
而 PG 崩溃时 Patroni 还活着,会主动尝试恢复 PG,primary_start_timeout 决定了等待多久才放弃。
fast 模式
最好结果
参数: loop_wait=5, primary_start_timeout=5, inter=1s, fastinter=500ms, rise=2, fall=2
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | PG 恰好在 HA loop 检查时崩溃 |
| 2 | Patroni 尝试重启 PG | 5s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 0s | 从库恰好在 HA loop 检查点 |
| 5 | 从库竞争 Leader 锁 | 0s | DCS 单次写操作 |
| 6 | 执行 pg_ctl promote | 1s | WAL 已同步,promote 快速完成 |
| 7 | HAProxy 检测新主 UP | 1s | rise=2 × fastinter=500ms |
| 总计 | | 7s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 5s | PG 恰好在 HA loop 刚结束时崩溃 |
| 2 | Patroni 尝试重启 PG | 5s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 5s | 从库 HA loop 恰好错过 |
| 5 | 从库竞争 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 7 | HAProxy 检测新主 UP | 2s | rise=2 × inter=1s(从 DOWN 状态开始) |
| 总计 | | 19s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 3s | loop_wait/2 |
| 2 | Patroni 尝试重启 PG | 5s | primary_start_timeout 固定 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 3s | loop_wait/2 |
| 5 | 从库竞争 Leader 锁 | 0s | DCS 操作平均延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 7 | HAProxy 检测新主 UP | 1s | rise=2 × fastinter |
| 总计 | | 12s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | 3s | 5s |
| 2 | Patroni 尝试重启 PG | 5s | 5s | 5s |
| 3 | 释放 Leader 锁 | 0s | 0s | 0s |
| 4 | 从库检测到 Leader 锁释放 | 0s | 3s | 5s |
| 5 | 从库竞争 Leader 锁 | 0s | 0s | 1s |
| 6 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 7 | HAProxy 检测新主 UP | 1s | 1s | 2s |
| 总计 | 7s | 12s | 19s |
fast 模式下 PG 崩溃场景 RTO 范围为 7s ~ 19s,平均约 12s。primary_start_timeout=5s 是固定成本,两个 loop_wait 周期(0~10s)是主要变量。此配置适合同机房低延迟环境,能快速完成故障切换。
norm 模式
参数: loop_wait=5, primary_start_timeout=15, inter=2s, fastinter=1s, rise=2, fall=3
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | PG 恰好在 HA loop 检查时崩溃 |
| 2 | Patroni 尝试重启 PG | 15s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 0s | 从库恰好在 HA loop 检查点 |
| 5 | 从库竞争 Leader 锁 | 0s | DCS 单次写操作 |
| 6 | 执行 pg_ctl promote | 1s | WAL 已同步,promote 快速完成 |
| 7 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 18s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 5s | PG 恰好在 HA loop 刚结束时崩溃 |
| 2 | Patroni 尝试重启 PG | 15s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 5s | 从库 HA loop 恰好错过 |
| 5 | 从库竞争 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 7 | HAProxy 检测新主 UP | 4s | rise=2 × inter=2s(从 DOWN 状态开始) |
| 总计 | | 31s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 3s | loop_wait/2 |
| 2 | Patroni 尝试重启 PG | 15s | primary_start_timeout 固定 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 3s | loop_wait/2 |
| 5 | 从库竞争 Leader 锁 | 0s | DCS 操作平均延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 7 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 23s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | 3s | 5s |
| 2 | Patroni 尝试重启 PG | 15s | 15s | 15s |
| 3 | 释放 Leader 锁 | 0s | 0s | 0s |
| 4 | 从库检测到 Leader 锁释放 | 0s | 3s | 5s |
| 5 | 从库竞争 Leader 锁 | 0s | 0s | 1s |
| 6 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 7 | HAProxy 检测新主 UP | 2s | 2s | 4s |
| 总计 | 18s | 23s | 31s |
norm 模式下 PG 崩溃场景 RTO 范围为 18s ~ 31s,平均约 23s。primary_start_timeout=15s 给了 PG 一定的本地恢复机会(如 crash recovery),同时保持了合理的 RTO。这是生产环境的推荐配置,平衡了故障恢复速度和误判风险。
safe 模式
参数: loop_wait=10, primary_start_timeout=60, inter=3s, fastinter=1s, rise=2, fall=3
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | PG 恰好在 HA loop 检查时崩溃 |
| 2 | Patroni 尝试重启 PG | 60s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 0s | 从库恰好在 HA loop 检查点 |
| 5 | 从库竞争 Leader 锁 | 0s | DCS 单次写操作 |
| 6 | 执行 pg_ctl promote | 1s | WAL 已同步,promote 快速完成 |
| 7 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 63s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 10s | PG 恰好在 HA loop 刚结束时崩溃 |
| 2 | Patroni 尝试重启 PG | 60s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 10s | 从库 HA loop 恰好错过 |
| 5 | 从库竞争 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 7 | HAProxy 检测新主 UP | 6s | rise=2 × inter=3s(从 DOWN 状态开始) |
| 总计 | | 88s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 5s | loop_wait/2 |
| 2 | Patroni 尝试重启 PG | 60s | primary_start_timeout 固定 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 5s | loop_wait/2 |
| 5 | 从库竞争 Leader 锁 | 1s | DCS 操作平均延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 7 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 73s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | 5s | 10s |
| 2 | Patroni 尝试重启 PG | 60s | 60s | 60s |
| 3 | 释放 Leader 锁 | 0s | 0s | 0s |
| 4 | 从库检测到 Leader 锁释放 | 0s | 5s | 10s |
| 5 | 从库竞争 Leader 锁 | 0s | 1s | 1s |
| 6 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 7 | HAProxy 检测新主 UP | 2s | 2s | 6s |
| 总计 | 63s | 73s | 88s |
safe 模式下 PG 崩溃场景 RTO 范围为 63s ~ 88s,平均约 73s。primary_start_timeout=60s 给大型数据库充足的 crash recovery 时间,降低不必要的 failover。此配置适合数据安全性要求极高、可容忍分钟级中断的场景。
wide 模式
参数: loop_wait=30, primary_start_timeout=120, inter=5s, fastinter=2s, rise=3, fall=5
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | PG 恰好在 HA loop 检查时崩溃 |
| 2 | Patroni 尝试重启 PG | 120s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 0s | 从库恰好在 HA loop 检查点 |
| 5 | 从库竞争 Leader 锁 | 1s | DCS 单次写操作(广域网延迟) |
| 6 | 执行 pg_ctl promote | 1s | WAL 已同步,promote 快速完成 |
| 7 | HAProxy 检测新主 UP | 6s | rise=3 × fastinter=2s |
| 总计 | | 127s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 30s | PG 恰好在 HA loop 刚结束时崩溃 |
| 2 | Patroni 尝试重启 PG | 120s | primary_start_timeout 固定等待 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 30s | 从库 HA loop 恰好错过 |
| 5 | 从库竞争 Leader 锁 | 2s | DCS 操作 + 广域网延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 7 | HAProxy 检测新主 UP | 15s | rise=3 × inter=5s(从 DOWN 状态开始) |
| 总计 | | 198s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 15s | loop_wait/2 |
| 2 | Patroni 尝试重启 PG | 120s | primary_start_timeout 固定 |
| 3 | 释放 Leader 锁 | 0s | 超时后立即释放 |
| 4 | 从库检测到 Leader 锁释放 | 15s | loop_wait/2 |
| 5 | 从库竞争 Leader 锁 | 1s | DCS 操作平均延迟 |
| 6 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 7 | HAProxy 检测新主 UP | 6s | rise=3 × fastinter=2s |
| 总计 | | 158s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | Patroni 检测到 PG 崩溃 | 0s | 15s | 30s |
| 2 | Patroni 尝试重启 PG | 120s | 120s | 120s |
| 3 | 释放 Leader 锁 | 0s | 0s | 0s |
| 4 | 从库检测到 Leader 锁释放 | 0s | 15s | 30s |
| 5 | 从库竞争 Leader 锁 | 1s | 1s | 2s |
| 6 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 7 | HAProxy 检测新主 UP | 6s | 6s | 15s |
| 总计 | 127s | 158s | 198s |
wide 模式下 PG 崩溃场景 RTO 范围为 127s ~ 198s(约 2~3 分钟),平均约 158s(约 3 分钟)。primary_start_timeout=120s 和 loop_wait=30s 提供极强的容错能力,适合广域网/跨数据中心部署。此配置优先保证不误判,代价是故障切换时间较长。
被动探测
手动触发
3 - 人工故障切换
人工触发 Failover / Switchover 下的的 RTO 计算逻辑与结果分析。
Switchover / Failover 场景(人工触发)RTO 对比
| 模式 | Switchover 平均 | Switchover 最坏 | Failover 平均 | Failover 最坏 |
|---|
| fast | 2s | 5s | 2s | 4s |
| norm | 4s | 8s | 3s | 6s |
| safe | 4s | 10s | 3s | 8s |
| wide | 9s | 21s | 9s | 17s |
Switchover(计划内优雅切换)
故障路径
准备阶段(老主库仍可用,不计入 RTO):
RTO 计时阶段(服务不可用):
RTO 计算公式:
RTO = WAL追平 + 锁切换 + promote + HAProxy_UP
RTO 构成分析
RTO = WAL追平 + 锁释放(~0.3s) + 锁获取(~0.2s) + promote(~0.5s) + HAProxy_UP
\______/
同步复制时为0
- WAL 追平:同步复制模式下为 0(已实时同步);异步复制时取决于复制延迟
- 锁切换:DCS 两次原子操作(释放 + 获取),约 0.3~1s
- HAProxy 延迟:
rise × fastinter
与 Failover 的差异
| 对比项 | Switchover | Failover |
|---|
| WAL 追平 | ✅ 等待(保证数据完整) | ❌ 跳过(可能丢数据) |
| 其他阶段 | 相同 | 相同 |
fast 模式
参数: inter=1s, fastinter=500ms, rise=2
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 0s | 同步复制,已完全同步 |
| 3 | 主库释放 Leader 锁 | 0s | DCS 原子操作 |
| 4 | 目标从库获取 Leader 锁 | 0s | DCS 原子操作 |
| 5 | 执行 pg_ctl promote | 1s | promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 1s | rise=2 × fastinter=500ms |
| 总计 | | 2s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 1s | 异步复制,存在少量延迟 |
| 3 | 主库释放 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 4 | 目标从库获取 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × inter=1s(从DOWN开始) |
| 总计 | | 5s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 0s | 少量复制延迟 |
| 3 | 主库释放 Leader 锁 | 0s | DCS 原子操作 |
| 4 | 目标从库获取 Leader 锁 | 0s | DCS 原子操作 |
| 5 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 1s | rise=2 × fastinter |
| 总计 | | 2s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 主库停止接受写入 | 0s | 0s | 0s |
| 2 | 等待从库 WAL 追平 | 0s | 0s | 1s |
| 3 | 主库释放 Leader 锁 | 0s | 0s | 1s |
| 4 | 目标从库获取 Leader 锁 | 0s | 0s | 1s |
| 5 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 6 | HAProxy 检测新主 UP | 1s | 1s | 2s |
| 总计 | 2s | 2s | 5s |
norm 模式
参数: inter=2s, fastinter=1s, rise=2
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 0s | 同步复制,已完全同步 |
| 3 | 主库释放 Leader 锁 | 0s | DCS 原子操作 |
| 4 | 目标从库获取 Leader 锁 | 0s | DCS 原子操作 |
| 5 | 执行 pg_ctl promote | 1s | promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 3s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 2s | 异步复制,存在复制延迟 |
| 3 | 主库释放 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 4 | 目标从库获取 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 4s | rise=2 × inter=2s(从DOWN开始) |
| 总计 | | 8s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 1s | 少量复制延迟 |
| 3 | 主库释放 Leader 锁 | 0s | DCS 原子操作 |
| 4 | 目标从库获取 Leader 锁 | 0s | DCS 原子操作 |
| 5 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 4s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 主库停止接受写入 | 0s | 0s | 0s |
| 2 | 等待从库 WAL 追平 | 0s | 1s | 2s |
| 3 | 主库释放 Leader 锁 | 0s | 0s | 1s |
| 4 | 目标从库获取 Leader 锁 | 0s | 0s | 1s |
| 5 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 6 | HAProxy 检测新主 UP | 2s | 2s | 4s |
| 总计 | 3s | 4s | 8s |
safe 模式
参数: inter=3s, fastinter=1s, rise=2
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 0s | 同步复制,已完全同步 |
| 3 | 主库释放 Leader 锁 | 0s | DCS 原子操作 |
| 4 | 目标从库获取 Leader 锁 | 0s | DCS 原子操作 |
| 5 | 执行 pg_ctl promote | 1s | promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 3s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 2s | 异步复制,存在复制延迟 |
| 3 | 主库释放 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 4 | 目标从库获取 Leader 锁 | 1s | DCS 操作 + 网络延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 6s | rise=2 × inter=3s(从DOWN开始) |
| 总计 | | 10s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 1s | 少量复制延迟 |
| 3 | 主库释放 Leader 锁 | 0s | DCS 原子操作 |
| 4 | 目标从库获取 Leader 锁 | 0s | DCS 原子操作 |
| 5 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 2s | rise=2 × fastinter=1s |
| 总计 | | 4s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 主库停止接受写入 | 0s | 0s | 0s |
| 2 | 等待从库 WAL 追平 | 0s | 1s | 2s |
| 3 | 主库释放 Leader 锁 | 0s | 0s | 1s |
| 4 | 目标从库获取 Leader 锁 | 0s | 0s | 1s |
| 5 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 6 | HAProxy 检测新主 UP | 2s | 2s | 6s |
| 总计 | 3s | 4s | 10s |
wide 模式
参数: inter=5s, fastinter=2s, rise=3
最好结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 0s | 同步复制,已完全同步 |
| 3 | 主库释放 Leader 锁 | 1s | DCS 原子操作(广域网延迟) |
| 4 | 目标从库获取 Leader 锁 | 1s | DCS 原子操作(广域网延迟) |
| 5 | 执行 pg_ctl promote | 1s | promote 快速完成 |
| 6 | HAProxy 检测新主 UP | 6s | rise=3 × fastinter=2s |
| 总计 | | 8s | |
最坏结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 3s | 异步复制 + 广域网复制延迟 |
| 3 | 主库释放 Leader 锁 | 2s | DCS 操作 + 广域网延迟 |
| 4 | 目标从库获取 Leader 锁 | 1s | DCS 操作 + 广域网延迟 |
| 5 | 执行 pg_ctl promote | 1s | promote + 少量 WAL 回放 |
| 6 | HAProxy 检测新主 UP | 15s | rise=3 × inter=5s(从DOWN开始) |
| 总计 | | 21s | |
平均结果
| 阶段 | 操作 | 耗时 | 说明 |
|---|
| 1 | 主库停止接受写入 | 0s | 即时生效 |
| 2 | 等待从库 WAL 追平 | 1s | 广域网复制延迟 |
| 3 | 主库释放 Leader 锁 | 1s | DCS 原子操作(广域网延迟) |
| 4 | 目标从库获取 Leader 锁 | 1s | DCS 原子操作(广域网延迟) |
| 5 | 执行 pg_ctl promote | 1s | promote 平均时间 |
| 6 | HAProxy 检测新主 UP | 6s | rise=3 × fastinter=2s |
| 总计 | | 9s | |
小结
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 主库停止接受写入 | 0s | 0s | 0s |
| 2 | 等待从库 WAL 追平 | 0s | 1s | 3s |
| 3 | 主库释放 Leader 锁 | 1s | 1s | 2s |
| 4 | 目标从库获取 Leader 锁 | 1s | 1s | 1s |
| 5 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 6 | HAProxy 检测新主 UP | 6s | 6s | 15s |
| 总计 | 8s | 9s | 21s |
Failover(强制切换)
故障路径
RTO 计算公式:
RTO = 验证 + 获取锁 + promote + HAProxy_UP
说明:Failover 通常在主库已故障时使用,此时 RTO 从执行命令开始计时(主库已不可用)。
fast 模式
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 验证候选从库 | 0s | 0s | 1s |
| 2 | 候选从库获取 Leader 锁 | 0s | 0s | 1s |
| 3 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 4 | HAProxy 检测新主 UP | 1s | 1s | 2s |
| 总计 | 2s | 2s | 4s |
norm 模式
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 验证候选从库 | 0s | 0s | 1s |
| 2 | 候选从库获取 Leader 锁 | 0s | 0s | 1s |
| 3 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 4 | HAProxy 检测新主 UP | 2s | 2s | 4s |
| 总计 | 3s | 3s | 6s |
safe 模式
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 验证候选从库 | 0s | 0s | 1s |
| 2 | 候选从库获取 Leader 锁 | 0s | 0s | 1s |
| 3 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 4 | HAProxy 检测新主 UP | 2s | 2s | 6s |
| 总计 | 3s | 3s | 8s |
wide 模式
| 阶段 | 操作 | 最好 | 平均 | 最坏 |
|---|
| 1 | 验证候选从库 | 1s | 1s | 1s |
| 2 | 候选从库获取 Leader 锁 | 1s | 1s | 2s |
| 3 | 执行 pg_ctl promote | 1s | 1s | 1s |
| 4 | HAProxy 检测新主 UP | 6s | 6s | 15s |
| 总计 | 8s | 9s | 17s |
人工触发汇总
Switchover vs Failover 对比
| 模式 | Switchover | | | Failover | | |
|---|
| 最好 | 平均 | 最坏 | 最好 | 平均 | 最坏 |
| fast | 2s | 2s | 5s | 2s | 2s | 4s |
| norm | 3s | 4s | 8s | 3s | 3s | 6s |
| safe | 3s | 4s | 10s | 3s | 3s | 8s |
| wide | 8s | 9s | 21s | 8s | 9s | 17s |
关键洞察
- Switchover 与 Failover RTO 非常接近
- 差异仅在于 WAL 追平时间(同步复制时为 0)
- 同步复制模式下,两者 RTO 几乎相同
- HAProxy 检测是主要延迟来源
- 在人工触发场景中,HAProxy UP 检测占总 RTO 的 43%~65%
- wide 模式下 HAProxy 延迟更为显著
- 与自动故障检测的对比
| 模式 | 人工 Switchover | 人工 Failover | 主动检测(PG崩溃) | 被动检测(节点宕机) |
|---|
| fast | 2s | 2s | 12s | 13s |
| norm | 4s | 3s | 23s | 24s |
| safe | 4s | 3s | 73s | 73s |
| wide | 9s | 9s | 158s | 128s |
人工触发比自动检测快 6~20 倍,因为跳过了 primary_start_timeout 和 TTL 等待 这两个最大的时间消耗。