20.4 选主、DCS 与防脑裂
PostgreSQL 原生提供 replication、promotion 与 recovery primitives,但不替 多台实例决定:
Patroni、DCS、watchdog 和 service routing 分别补上这条链的不同环节。 把它们都叫“自动选主”,会丢掉最重要的安全边界。
20.4.1 Patroni、租约、leader lock 与健康判断
leader 是有期限的 authority
Patroni 使用 DCS 中的 leader key/lock 表达:
它不是永久铭牌。当前 leader 必须周期性更新;失去更新能力时,旧 authority 必须在新的 candidate 可能获得 authority 之前失效。
关键周期:
本章实际 dynamic policy:
这些值共同影响 detection 与 decision latency。不能只拿 ttl=30 直接写出
“RTO=30s”,还需 health path、fence、promotion、service check 与 client
recovery。
health 有多个观察层
Patroni candidate eligibility 可能考虑:
服务代理又可能使用 Patroni REST endpoint:
客户端 SQL 则看到:
三层应当一致,但 authority 不同:
| 证据 | 回答 |
|---|---|
| DCS/Patroni | 谁拥有 HA authority |
| PostgreSQL SQL | 当前实例是否 recovery、复制事实 |
| service health/routing | 新连接会被送到谁 |
| client transaction | 业务是否恢复且结果可判断 |
只看一层无法完成 HA acceptance。
patronictl list 是快照
它适合:
但输出不是审计历史,也不证明旧主已物理隔离。正式实验把结构化 JSON 与 SQL phase 一起保存,而不是只贴一张终端截图。
candidate “最新”也需要定义
异步集群可能没有一个 candidate 包含 primary 的最后 WAL tail。Patroni
maximum_lag_on_failover 控制候选落后上限的一部分,但官方文档指出位置
并非实时连续采样,实际 worst case 还包括最近一个周期生成的 WAL。
所以:
不是:
更不是 zero RPO。
timeline eligibility
同 system identifier 的旧分支 member 也可能不适合提升。check_timeline
等政策可限制 candidate timeline;本章没有把未观察的配置写成已启用。
正式验收另行要求:
这是针对本次 planned transition 的 lineage proof。
pause 与 maintenance
Patroni paused mode 会改变自动管理行为。任何切换前都要显式查看:
本章 preflight 要求 pause=false。如果 cluster paused:
- 不应假设自动 failover 会工作;
- 不应直接照抄 runbook;
- 先确认是谁、为何 pause,以及安全恢复路径。
DCS 是协调 authority,不是数据真相
DCS 保存 leader lock、dynamic config 和 member metadata;业务行仍在 PostgreSQL,WAL lineage 由 PostgreSQL 证明。
不应:
HA 要求 coordination truth 与 data-plane truth 对齐。
20.4.2 fencing、watchdog 与旧主隔离
脑裂是什么
不是监控上短暂出现两个 running,而是:
尤其危险的状态:
事后不能靠 WAL replication 自动 merge 两边业务。
fencing 的目标
在新 primary 接受写之前,确保旧 primary:
fence 可以在不同层实现:
| 层 | 手段 | 局限 |
|---|---|---|
| process | Patroni stop/demote PostgreSQL | Patroni 若失调度可能失败 |
| host | watchdog reset、STONITH | 需真实硬件/权限/验证 |
| storage | revoke writer attachment/lease | 依赖 storage semantics |
| network/service | proxy 不路由旧主 | 直连可能绕过 |
| application | authority token/epoch | 应用复杂度高,仍需底层安全 |
多层互补,不能拿 HAProxy health check 替代 host fencing。
为什么 stop 也可能来不及
此时普通“租约更新失败后 stop PostgreSQL”逻辑可能没有机会及时执行。
watchdog
Linux watchdog 接收 heartbeat;超过窗口未喂狗,系统被 reset。Patroni 在 成为 leader 前可以激活 watchdog,并在 demotion 后禁用。
重要模式:
准确名称和行为以所用 Patroni 版本为准。
本章实际:
所以正式结论必须保留:
不能因为 planned switchover 中旧主正常 demote/rejoin,就宣称 VM pause 或 Patroni crash 时也安全。
service routing 是最后一道,但不是唯一一道
Pigsty primary service 通常用 Patroni /primary health check,只把新连接
送给当前 primary。即使旧 PostgreSQL 进程还可接受直连,只要 Patroni API
不再报告 primary,HAProxy 可以停止把 primary service 流量送过去。
这很有价值,但有边界:
生产必须治理直连权限与网络路径,而不是只发布“推荐使用 5433”。
fence proof
一个未计划故障演练至少应证明:
本章没有注入这类 fault,因此不声称完成。
手工 promote 是高风险动作
当 DCS/网络视图不清楚时:
不是“恢复服务的快捷键”,而是选择一条新可写历史。操作前必须知道:
不满足就 stop,而不是用 --force 消除不确定性。
20.4.3 DCS 可用性与数据库可用性不是同一件事
两种 availability
DCS outage 时,已有 primary 可能短时仍有数据服务;同时系统无法安全建立新 authority。这不是矛盾,而是两个 control boundary。
为什么失去 DCS 时通常选择保守
单个 member 无法仅凭“我连不上 DCS”区分:
如果它乐观继续写,另一侧又选主,就可能脑裂。因此传统安全选择是:
Patroni DCS failsafe mode
failsafe_mode 试图在特定 DCS failure 中保留已有 primary:
若任何已知 member 不响应,则 demote。Patroni DCS failsafe 文档 强调检查 all members,而不是随意取 Patroni member 多数,因为 DCS 与 PostgreSQL placement quorum 可能不是同一个视图。
本章观察 failsafe_mode=true,但没有让 etcd 失效或切网络,因此:
单节点 etcd 不是 HA DCS
正式沙箱只有一个 etcd member:
它足以验证:
不能验证:
这就是 EX19-SINGLE-ETCD 在第 20 章继续生效的原因。
DCS 也有自己的运维合同
生产需要:
不要让一个为数据库提供 HA 的组件,自己成为没人负责的单点。
control-plane outage runbook
建议先判断:
禁止:
数据面正常时也要保留事故证据
若 client 暂时无感,不代表无需 incident:
应记录:
本章的停止线
只要出现:
就不继续 planned switchover,也不自动尝试“恢复”。先冻结写路径、保留证据、 升级 decision authority。
本节证据
当前三台 member 都要报告:
dynamic config 必须来自 DCS:
公开采集器只导出 allowlist,不把完整 Patroni YAML 中的 credential 复制进 evidence。
小结
权威参考
- Patroni:DCS failsafe mode
- Patroni:Watchdog support
- Patroni:Replication modes
- Pigsty:High Availability
- 本章 live policy capture
上一节:同步策略与提交语义 · 返回本章目录 · 下一节:切换、故障转移与重加入 · 查看全书目录 · 查看索引中心