跳至内容
33.3 自动故障转移的保护条件

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 timeline

ttlloop_waitretry_timeout 会影响探测和选举节奏,但端到端 RTO 还包括 PostgreSQL 停止/恢复、DCS 延迟、候选 replay、代理健康检查、连接重建和客户端重试。

33.3.1 候选健康、数据风险与多数判断

候选先通过资格门

候选至少需要:

条件目的证据
Patroni REST 可达能参与管理与健康检查exact endpoint/status
同 system identifier属于同一物理 lineagepg_control_system()
WAL/timeline 可接受不跳回旧分支LSN、history、check_timeline
lag 在策略内控制异步数据风险pg_stat_replication 与 policy
nofailover=false未被运维策略排除Patroni tags
replay 未异常暂停promotion 后能完成 recoveryrecovery/receiver state
required watchdog 可用满足本节点 leader 前提Patroni/watchdog status
同步模式条件满足遵守 sync/quorum policyDCS 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 stoppostmaster 不再写I/O hang 时可能无法完成
Patroni demote/stop角色管理与数据库按协议停止控制进程自身可能失效
watchdog resetPatroni 未续喂时节点重启设备/权限/超时配置必须真实可用
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 支持 offautomaticrequired。本章沙箱为 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:

  1. 阻断外部写,记录每条路由与 writer;
  2. 保存两边 system identifier、timeline、LSN 与业务 identity;
  3. 取得至少一边的可信 fence;
  4. 由业务 authority 选择权威分支;
  5. 隔离提取另一分支独有的合法事实;
  6. 用逻辑对账合并,而不是直接让它重新加入;
  7. 从权威分支 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 failoverleader 不可用且自动路径不能完成必须明确 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 故障的安全处理 · 查看全书目录 · 查看索引中心

最后更新于