33.3 自动故障转移的保护条件
自动故障转移的价值,是在预先证明过的条件内缩短决策时间;它不是在信息不足时替人 猜测。一个安全状态机应当宁可暂时没有可写主库,也不接受两个相互冲突的写 authority。
简化后的 Patroni 路径:
incumbent loop
-> renew leader lock
-> success: remain primary
-> failure:
distinguish lock loss from transient DCS error as far as possible
demote, or enter preconfigured failsafe checks
replica loop
-> observe no valid leader
-> verify eligibility and data state
-> leader race through DCS
-> winner promotes
-> others follow the new timelinettl、loop_wait 与 retry_timeout 会影响探测和选举节奏,但端到端 RTO 还包括
PostgreSQL 停止/恢复、DCS 延迟、候选 replay、代理健康检查、连接重建和客户端重试。
33.3.1 候选健康、数据风险与多数判断
候选先通过资格门
候选至少需要:
| 条件 | 目的 | 证据 |
|---|---|---|
| Patroni REST 可达 | 能参与管理与健康检查 | exact endpoint/status |
| 同 system identifier | 属于同一物理 lineage | pg_control_system() |
| WAL/timeline 可接受 | 不跳回旧分支 | LSN、history、check_timeline |
| lag 在策略内 | 控制异步数据风险 | pg_stat_replication 与 policy |
nofailover=false | 未被运维策略排除 | Patroni tags |
| replay 未异常暂停 | promotion 后能完成 recovery | recovery/receiver state |
| required watchdog 可用 | 满足本节点 leader 前提 | Patroni/watchdog status |
| 同步模式条件满足 | 遵守 sync/quorum policy | DCS sync state |
“候选服务可连”没有覆盖这些条件。一个被刻意延迟 30 分钟的 reporting replica 可能非常 健康,却绝不能自动成为业务主库。
三种“多数”不要混为一谈
DCS quorum
DCS 自己能否形成一致写 authority
PostgreSQL replicas
有多少数据节点仍活着、各自有哪些 WAL
business commit quorum
当前提交策略要求多少同步确认三节点 PostgreSQL 加单节点 etcd,并不会因为“数据库还有 2/3”就拥有 DCS 多数; 三节点 etcd 加两节点 PostgreSQL,也不会自动使 PostgreSQL 写入成为多数派复制。DCS 负责协调 leader authority,WAL durability 由 PostgreSQL replication mode 决定。
生产设计需要分别画失败域:
etcd member placement odd count, independent failure domains
PostgreSQL placement required data/availability tolerance
sync policy commit latency and data-loss budget
client route which authority is actually reachable
fence how an isolated incumbent loses write ability异步可用性换取数据风险
默认异步模式允许 primary 在副本未确认时提交。故障后提升某个 sufficiently healthy
standby,未复制到它的事务会留在旧分支。maximum_lag_on_failover 限制候选在最近
观测时的 WAL gap,却不覆盖观测后到故障间的新 WAL。
所以报告应写:
policy lag threshold 1 MiB
observed replay gap at timestamp exact bytes
last client acknowledgement token
unknown outcome count N
post-failover reconciliation result而不是只写 RPO < 1MB。WAL 字节不是业务订单数,unknown 也不等于丢失。
同步模式能收紧正常单故障的数据风险,但也有可用性和复合故障边界。切换报告仍应验证 业务 identity,不把配置名当作结果。
自动选择不等于随机选择
Patroni 按当前资格与状态参与 leader race;操作者不应从成员列表顺序推断赢家。本章
正式 run 的两个 replica 都合格,实际 pg-test-3 提升。正确验收是:
winner in eligible set
winner is unique running primary
other eligible replica remains streaming
old primary was fenced before acceptance如果业务要求指定节点,使用 planned switchover 或明确 tags/拓扑策略,不能把自动选举 伪装成固定候选。
33.3.2 fencing 旧主与防止双写
fence 的目标是消除旧 authority
旧主围栏的验收谓词:
$$ CanWrite(old) = false $$
或者在特殊设计中:
$$ CanProduceAcceptedEffects(old) = false $$
第二种更难证明,因为必须覆盖所有客户端、job、CDC、消息和外部副作用。数据库 HA 通常优先选择第一种:让 PostgreSQL 停止、只读、失去存储或节点断电。
围栏层次
| fence | 能证明 | 主要盲点 |
|---|---|---|
| PostgreSQL clean stop | postmaster 不再写 | I/O hang 时可能无法完成 |
| Patroni demote/stop | 角色管理与数据库按协议停止 | 控制进程自身可能失效 |
| watchdog reset | Patroni 未续喂时节点重启 | 设备/权限/超时配置必须真实可用 |
| BMC/cloud power off | 主机失去计算能力 | 控制面状态延迟、自动重启策略 |
| storage detach/revoke | 旧主失去可写数据 | 本地缓存、detach 完成语义 |
| network isolation | 阻断已枚举的路径 | 漏掉网络、job 或控制路径 |
| proxy/backend removal | 正常服务不再路由 | 不是数据库 fence |
Patroni watchdog 是一层额外保护:若 mode 为 required 且不能启用 watchdog,节点拒绝
成为 leader;leader 正常运行时必须持续喂狗,否则 watchdog 在超时后触发 reset。它
不能只存在配置文件里,演练要验证设备、权限、超时和真实 reset。
Pigsty 的 patroni_watchdog_mode 支持 off、automatic、required。本章沙箱为
off,所以正式 run 明确只声称 process fence,不声称硬件 watchdog。
顺序不变量
t0 fault action starts
t1 old primary fence independently verified
t2 eligible candidate becomes unique primary
t3 service health accepts new primary
t4 first new-timeline business write acknowledged要求 $t_1 \le t_2$。如果无法观测真实 promotion 瞬间,至少在“接受候选为可服务” 之前完成 fence evidence;不要用事后日志倒推一个未经保护的时间窗不存在。
本章正式结果:
action -> process fence 1.817 s
action -> Patroni stable 4.536 s
fence before stable true
old service active false
old postmaster alive false
old REST reachable false这是一台可控虚拟机上的 graceful systemd stop。主机断电、内核 hang 与存储 stall 需要不同 fence,不能复用这组时延。
双主之后不要急着“选数据多的”
若已经观察到两个 writable primary:
- 阻断外部写,记录每条路由与 writer;
- 保存两边 system identifier、timeline、LSN 与业务 identity;
- 取得至少一边的可信 fence;
- 由业务 authority 选择权威分支;
- 隔离提取另一分支独有的合法事实;
- 用逻辑对账合并,而不是直接让它重新加入;
- 从权威分支 rewind 或全量重建 loser。
pg_rewind 会舍弃 target 的分叉变化。未先抢救业务事实就 rewind,等于主动销毁可能
需要审计的数据。
33.3.3 自动化不确定时何时转人工
转人工的含义
转人工不是自动执行:
patronictl failover ... --force它意味着把状态机停在安全边界,要求人补齐:
current accepted authority
old-primary fence mechanism and evidence
candidate identity and lineage
data-loss upper bound / unknown set
service route owner
rollback or rebuild path
production authorization三种切换入口
| 入口 | 适用 | leader/candidate | 风险 |
|---|---|---|---|
| automatic failover | 已验证故障与预设策略内 | 由 Patroni/DCS 竞选 | 策略边界内自动 |
| planned switchover | 健康 leader 的维护切换 | 可显式指定 | 可预检、通常低风险 |
| manual failover | leader 不可用且自动路径不能完成 | 必须明确 candidate | 可能放宽 lag/sync 条件并丢数据 |
Patroni REST 文档明确警告 manual failover 可能导致数据损失;无 leader 时,手工候选 可能不受自动 failover 的全部 lag/sync 检查。它是一项风险接受,不是“更强的修复命令”。
Pig 的入口:
pig pt list pg-test -o json
pig pt switchover --plan
pig pt failover --candidate <member> --plan
pig pt reinit <replica> --plan--plan 只展示工具计划,不能替代 fence 与 SQL 证据。执行参数以现场 --help 为准;
structured execution 通常还要求显式确认。
自动化停止线
| 不确定性 | 自动动作 |
|---|---|
| old primary writable? unknown | 禁止接受新主 |
| candidate lineage unknown | 禁止 promote |
| DCS split direction unknown | 禁止删 key/重建 DCS |
| manual candidate lag unknown | 禁止 force failover |
| client unknown outcomes unbounded | 可以恢复服务,但不能宣称 RPO |
| backup/archive health unknown | 可以先恢复 HA,必须保持生产 gate pending |
自动化可以并行采集和收敛证据,但不能把超时本身当作安全事实。一个 60 秒 timeout 只能 证明“在观察位置没看到预期状态”,不能证明旧主已经断电。
人工决策记录
decision: accept-candidate | retain-incumbent | stop-writes | rebuild
decided_at: UTC
decision_owner: incident-commander
facts:
- evidence-id
hypotheses:
- statement-and-test
data_risk:
last_ack: token
unknown: manifest
accepted_loss: explicit
fence:
target: old-primary
mechanism: exact
independently_verified_by: role
stop_condition: exact
rollback: exact没有这份记录的 --force,在复盘时无法区分有意识的风险接受与操作失误。
上一节:复制状态与时间线证据 · 返回本章目录 · 下一节:DCS 故障的安全处理 · 查看全书目录 · 查看索引中心