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 表达:
某 member 在一个租约窗口内拥有 primary authority它不是永久铭牌。当前 leader 必须周期性更新;失去更新能力时,旧 authority 必须在新的 candidate 可能获得 authority 之前失效。
关键周期:
ttl
leader lock 的租约尺度
loop_wait
HA loop 大致运行间隔
retry_timeout
DCS 操作重试边界本章实际 dynamic policy:
ttl=30
loop_wait=5
retry_timeout=10
maximum_lag_on_failover=1048576
pause=false
failsafe_mode=true这些值共同影响 detection 与 decision latency。不能只拿 ttl=30 直接写出
“RTO=30s”,还需 health path、fence、promotion、service check 与 client
recovery。
health 有多个观察层
Patroni candidate eligibility 可能考虑:
member API alive
PostgreSQL state
replication state and lag
timeline
tags: nofailover/nosync/...
scheduled maintenance
sync safety state服务代理又可能使用 Patroni REST endpoint:
/primary
/replica
/read-only客户端 SQL 则看到:
SELECT pg_is_in_recovery();三层应当一致,但 authority 不同:
| 证据 | 回答 |
|---|---|
| DCS/Patroni | 谁拥有 HA authority |
| PostgreSQL SQL | 当前实例是否 recovery、复制事实 |
| service health/routing | 新连接会被送到谁 |
| client transaction | 业务是否恢复且结果可判断 |
只看一层无法完成 HA acceptance。
patronictl list 是快照
sudo -iu postgres \
patronictl -c /etc/patroni/patroni.yml \
list pg-test它适合:
member/host
role/state
timeline
lag snapshot
scheduled actions但输出不是审计历史,也不证明旧主已物理隔离。正式实验把结构化 JSON 与 SQL phase 一起保存,而不是只贴一张终端截图。
candidate “最新”也需要定义
异步集群可能没有一个 candidate 包含 primary 的最后 WAL tail。Patroni
maximum_lag_on_failover 控制候选落后上限的一部分,但官方文档指出位置
并非实时连续采样,实际 worst case 还包括最近一个周期生成的 WAL。
所以:
maximum_lag_on_failover=1 MiB不是:
RPO always <= exactly 1 MiB更不是 zero RPO。
timeline eligibility
同 system identifier 的旧分支 member 也可能不适合提升。check_timeline
等政策可限制 candidate timeline;本章没有把未观察的配置写成已启用。
正式验收另行要求:
all current members report same Patroni timeline per phase
primary WAL-derived timeline agrees
timeline advances on both switchovers
system identifier never changes这是针对本次 planned transition 的 lineage proof。
pause 与 maintenance
Patroni paused mode 会改变自动管理行为。任何切换前都要显式查看:
patronictl show-config pg-test本章 preflight 要求 pause=false。如果 cluster paused:
- 不应假设自动 failover 会工作;
- 不应直接照抄 runbook;
- 先确认是谁、为何 pause,以及安全恢复路径。
DCS 是协调 authority,不是数据真相
DCS 保存 leader lock、dynamic config 和 member metadata;业务行仍在 PostgreSQL,WAL lineage 由 PostgreSQL 证明。
不应:
只因 DCS 里写着 leader 就忽略 SQL recovery state
只因 SQL 可写就绕过 DCS authority
把 DCS backup 当 PostgreSQL backupHA 要求 coordination truth 与 data-plane truth 对齐。
20.4.2 fencing、watchdog 与旧主隔离
脑裂是什么
不是监控上短暂出现两个 running,而是:
two diverging histories can accept writes尤其危险的状态:
old primary retains client reachability
old primary lost DCS authority
new primary acquired authority
different clients write both sides事后不能靠 WAL replication 自动 merge 两边业务。
fencing 的目标
在新 primary 接受写之前,确保旧 primary:
stopped
demoted read-only
power/storage/network fenced
or otherwise unreachable from all write clientsfence 可以在不同层实现:
| 层 | 手段 | 局限 |
|---|---|---|
| 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 也可能来不及
Patroni process crashed/OOM
PostgreSQL shutdown too slow
host load high
VM paused
HA loop not scheduled此时普通“租约更新失败后 stop PostgreSQL”逻辑可能没有机会及时执行。
watchdog
Linux watchdog 接收 heartbeat;超过窗口未喂狗,系统被 reset。Patroni 在 成为 leader 前可以激活 watchdog,并在 demotion 后禁用。
重要模式:
off
不提供 watchdog fence
automatic
可用时使用
required
不能激活就拒绝成为 leader准确名称和行为以所用 Patroni 版本为准。
本章实际:
watchdog.mode=off
device=/dev/watchdog
safety_margin=5所以正式结论必须保留:
EX20-WATCHDOG-OFF
hardware-watchdog fencing unqualified不能因为 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 流量送过去。
这很有价值,但有边界:
direct 5432/6432 connections can bypass service
stale existing sessions may differ from new routing
another network path may still reach old primary
health endpoint itself depends on Patroni process生产必须治理直连权限与网络路径,而不是只发布“推荐使用 5433”。
fence proof
一个未计划故障演练至少应证明:
old primary loses authority before/when new authority starts
old primary cannot accept write through any authorized path
client service selects only new primary
old primary later rejoins chosen timeline or is rebuilt
logs/DCS timeline explain ordering本章没有注入这类 fault,因此不声称完成。
手工 promote 是高风险动作
当 DCS/网络视图不清楚时:
pg_ctl promote
patronictl failover --force不是“恢复服务的快捷键”,而是选择一条新可写历史。操作前必须知道:
old primary state
candidate WAL position/timeline
who has authority
which clients are drained
what data loss is accepted
how old primary will be fenced不满足就 stop,而不是用 --force 消除不确定性。
20.4.3 DCS 可用性与数据库可用性不是同一件事
两种 availability
database availability
当前 authorized primary 能否继续完成事务
HA control availability
系统能否安全更新 lock、选新 primary、改变动态配置DCS outage 时,已有 primary 可能短时仍有数据服务;同时系统无法安全建立新 authority。这不是矛盾,而是两个 control boundary。
为什么失去 DCS 时通常选择保守
单个 member 无法仅凭“我连不上 DCS”区分:
DCS 全部 down
自己被网络隔离
另一侧仍可达 DCS 并会选新 leader如果它乐观继续写,另一侧又选主,就可能脑裂。因此传统安全选择是:
cannot renew authority -> demote before lease expiryPatroni DCS failsafe mode
failsafe_mode 试图在特定 DCS failure 中保留已有 primary:
current leader cannot update DCS
but can reach all known Patroni members via REST
all members acknowledge it
then it may continue as primary若任何已知 member 不响应,则 demote。Patroni DCS failsafe 文档 强调检查 all members,而不是随意取 Patroni member 多数,因为 DCS 与 PostgreSQL placement quorum 可能不是同一个视图。
本章观察 failsafe_mode=true,但没有让 etcd 失效或切网络,因此:
configured intent observed
behavior under DCS loss not tested单节点 etcd 不是 HA DCS
正式沙箱只有一个 etcd member:
dcs_endpoint_count=1它足以验证:
Patroni integration
leader lock path
planned switchover
dynamic config capture不能验证:
DCS quorum survives one member loss
cross-AZ DCS placement
etcd election latency
split network behavior这就是 EX19-SINGLE-ETCD 在第 20 章继续生效的原因。
DCS 也有自己的运维合同
生产需要:
odd-sized quorum where appropriate
independent placement
latency budget
capacity/compaction
TLS and identity
backup/restore
version/upgrade
monitoring
access control不要让一个为数据库提供 HA 的组件,自己成为没人负责的单点。
control-plane outage runbook
建议先判断:
1. current PostgreSQL client service still可用吗?
2. leader lock最后一次成功更新是什么时候?
3. DCS 是全局 down 还是局部 partition?
4. current leader 能否看到所有 Patroni members?
5. watchdog/fence 是否真实有效?
6. 是否允许保持 current leader,还是必须冻结写?
7. 谁有权执行 manual action?禁止:
simultaneously restart every Patroni/DCS member
force promote while old primary unknown
delete DCS keys to “reset state”
initialize a new DCS namespace without lineage proof数据面正常时也要保留事故证据
若 client 暂时无感,不代表无需 incident:
HA redundancy may be gone
next fault may become outage
dynamic config changes may be unavailable
leader authority safety margin is reduced应记录:
first/last DCS error
member reachability matrix
leader loop logs
lease/TTL
failsafe requests
client SLI
manual actions本章的停止线
只要出现:
two possible leaders
unknown old-primary write reachability
system identifier mismatch
ambiguous timeline
DCS authority absent and failsafe condition unproven就不继续 planned switchover,也不自动尝试“恢复”。先冻结写路径、保留证据、 升级 decision authority。
本节证据
当前三台 member 都要报告:
scope=pg-test
member_name exact
patroni_version=4.1.3
dcs_kind=etcd3
dcs_endpoint_count=1
watchdog.mode=offdynamic config 必须来自 DCS:
ttl=30
loop_wait=5
retry_timeout=10
maximum_lag_on_failover=1048576
synchronous_mode=false
failsafe_mode=true
pause=false
use_pg_rewind=true
use_slots=true公开采集器只导出 allowlist,不把完整 Patroni YAML 中的 credential 复制进 evidence。
小结
leader is leased authority
health is layered evidence
election without fencing can still split brain
watchdog protects when user-space demotion may not run
service routing is necessary but bypassable
DCS availability != database availability
configured failsafe != tested failsafe
single etcd blocks production HA inference权威参考
- Patroni:DCS failsafe mode
- Patroni:Watchdog support
- Patroni:Replication modes
- Pigsty:High Availability
- 本章 live policy capture
上一节:同步策略与提交语义 · 返回本章目录 · 下一节:切换、故障转移与重加入 · 查看全书目录 · 查看索引中心