33.4 DCS 故障的安全处理
Patroni 依赖 DCS 保存 leader lock、动态配置与成员协调状态。某节点无法更新 leader lock, 可能是 DCS 整体故障,也可能是该节点落在网络分区的错误一侧。从单个节点看,两者很难 区分:
I cannot reach DCS
!= DCS has no quorum
!= nobody else can reach DCS
!= I am still the accepted primary安全默认是按最坏分区处理:旧主不能续约 authority,就要在 lease 失效前停止写,避免
另一侧取得 lock 后出现双主。failsafe_mode 是一个有严格条件的例外,不是忽略 DCS。
33.4.1 DCS 不可达、失去多数与延迟
先区分四种现象
| 现象 | 可能原因 | 不能立即做 |
|---|---|---|
| 一个 Patroni 到 DCS 超时 | 节点网络、DNS、凭据、DCS | 宣称 DCS 整体宕机 |
| 所有 Patroni 到 DCS 失败 | DCS 失去 quorum、公共网络 | 直接 bootstrap 新 DCS |
| DCS 请求慢但可成功 | 负载、磁盘、网络、GC | 只调大 TTL 掩盖 |
| DCS 有 quorum,某分区不可见 | 不对称网络 | 在不可见一侧手工提升 |
调查矩阵:
each PostgreSQL member -> every configured DCS endpoint
each DCS member -> DCS peers
current primary -> every known Patroni REST endpoint
replicas -> current primary REST endpoint
observer/client -> current SQL service同时记录 UTC、monotonic clock、请求耗时和 DCS revision。只记录一次
endpoint health=true 会漏掉尾延迟和间歇超时;只看平均值又会漏掉超过
retry_timeout/lease deadline 的长尾。
DCS 多数派属于 DCS
etcd 通常部署奇数成员。三成员容忍一成员故障,五成员容忍两成员故障;单成员没有 冗余。PostgreSQL 数据节点数量不会补足 etcd quorum。
Pigsty 生产设计应让 infra/DCS 与 PostgreSQL failure domain 相互审阅:
- DCS 成员跨独立电源、主机或可用区;
- latency 满足 lease 与运维目标;
- client/peer 网络和证书可用;
- 备份 DCS 配置与凭据恢复流程,但不把陈旧快照直接覆盖活集群;
- 监控 leader changes、fsync、peer RTT、容量与 auth failure;
- 演练成员故障和 quorum 丢失,不只测
systemctl status。
本章沙箱只有一个 etcd,不能演示多数派。正式实验因此不停止 DCS,只用 blind decision scenario 验证 runbook。
延迟故障比“down”更隐蔽
DCS 还能响应,但延迟接近 Patroni deadline 时可能出现:
leader loop misses renewal window
members observe stale or alternating state
CLI intermittently fails
health check remains green for part of the interval
clock and log ordering become hard to compare正确动作是保存 latency distribution、Patroni loop 时间和 lease revision,处理控制面
性能根因。盲目增大 ttl 会延长故障检测与服务恢复;盲目减小又会让正常长尾触发抖动。
参数变更必须作为容量与失败注入实验,而不是事故现场的猜测。
33.4.2 先保护当前数据库角色,不盲目重置选举状态
failsafe_mode 的严格语义
Patroni DCS failsafe mode 启用后,incumbent primary 在 DCS leader lock 更新因特定
连接类错误失败时,可以向 /failsafe 中全部已知成员发送 Patroni REST 请求。
只有全部成员确认它仍是当前 primary,它才可以继续作为 primary。
为什么不是多数副本确认?DCS quorum 的网络分区与 PostgreSQL 成员分布可能不同。如果 primary 只联系到某个“数据库多数”,DCS 可写分区里的少数 PostgreSQL 节点仍可能取得 leader lock。要求 ALL known members,才能让任何可能竞选的成员知道 incumbent 仍活着。
因此:
failsafe_mode = true
does not mean "primary ignores DCS"
does not mean "majority of replicas is enough"
does not create WAL durability
does not rescue an unknown /failsafe membership若已知成员之一不可达,incumbent 应 demote;DCS 恢复前不会凭空得到新的 authority。
不要删除你还没理解的 key
危险动作:
delete leader key
delete /config or /failsafe
wipe DCS data directory
bootstrap a second independent DCS
restore a stale DCS snapshot over live quorum
pause/resume without recording current state
manually promote PostgreSQL outside Patronileader key 是协调事实,不是“卡住的锁文件”。删除它会触发新的 leader race,却不会 自动停止旧主;如果旧主仍写,删除 key 正好制造双主窗口。
先保护:
- 当前 SQL 角色和客户端写入口;
- leader lock、revision、member 与 failsafe 内容;
- 每个 Patroni 的 REST 角色与可达性;
- DCS member/quorum 与 auth 状态;
- 旧主 fence 能力;
- WAL/archive/backup 现场。
需要禁止写时,围住精确业务入口或数据库 authority,不要用破坏 DCS 历史的方式达到 “看起来没主库”。
六个决策场景
本章 failure-model.json 固定六种:
| 场景 | 默认决策 |
|---|---|
| 所有 Patroni 失去 DCS、彼此 REST 全可达 | 观察 failsafe incumbent,不发起新竞选 |
| 仅 primary 失去 DCS、可达全部成员 | 验证 failsafe handshake,replica 不竞选 |
| primary 失去 DCS 且看不到一名已知成员 | old primary 必须 demote/fence 后才接受候选 |
| 仅 replica 失去 DCS | 排除该 replica,保持当前 primary |
| DCS latency 接近 timeout | 控制面事故,停止人工 promotion,保存时间证据 |
| 代理故障伪装成数据库故障 | 修服务路径,不切数据库 |
正式 run 随机抽到“primary 同时失去 DCS 和一个 replica”。正确答案不是立即 promote, 而是先证明旧主只读/停止或由外部 fence 隔离,再确认幸存侧的 DCS authority 与候选 WAL。本次只做决策演练,没有真实注入分区。
33.4.3 恢复控制面后核对 leader lock 与数据库事实
恢复顺序
1 restore DCS quorum and stable latency
2 keep application writes fenced if authority is ambiguous
3 read leader lock, config, sync/failsafe and member records
4 query Patroni REST on every PostgreSQL member
5 query pg_is_in_recovery and lineage on every reachable database
6 resolve contradictions and fence losers
7 allow one authority to remain/become primary
8 restore replicas, service routing and client traffic
9 verify monitoring, archive and backup不要在第 1 步完成后直接开放流量。DCS 恢复只说明控制面重新可读写,数据库可能已经有 两个分支或有成员保留陈旧角色。
四层互证表
| 层 | 唯一主库应看到 | 异常例子 |
|---|---|---|
| DCS | one valid leader lock | no lock / stale identity |
| Patroni REST | one primary with lock, replicas elsewhere | two primaries / unknown |
| SQL | accepted node recovery=false,followers=true | DCS leader SQL 仍 recovery |
| service | write health only points accepted primary | old backend remains healthy |
如果 DCS 指向 A、SQL 却显示 A 在 recovery、B 可写,不要为了让表格一致而手改 key。 先停止流量,保存两边日志、control data 和 timeline,查明谁何时改变角色。
推荐证据命令
pig pt list pg-test -o json
pig pt config show -o json
curl --fail --silent http://<member>:8008/patroniSQL:
SELECT
pg_is_in_recovery(),
(pg_control_system()).system_identifier,
(pg_control_checkpoint()).timeline_id,
pg_last_wal_receive_lsn(),
pg_last_wal_replay_lsn();在 primary 上另查 pg_stat_replication;在 replica 上查 pg_stat_wal_receiver。所有
输出带采集位置、UTC、monotonic sequence 与 hash。REST/DCS 可能含敏感认证信息,证据
包只保留必要 projection,不导出密码、token 或完整配置。
DCS 恢复完成标准
dcs:
quorum: healthy
latency_budget: passed
leader_lock: exact-member-and-revision
config_hash: expected
failsafe_members: reconciled
database:
accepted_primary: exact-member
old_primary_fenced_or_replica: true
system_identifier_relation: one
timeline_history: admissible
service:
write_backend: accepted-primary-only
stale_connections_reconciled: true
replication:
all_expected_members_streaming: true
slots_and_archive: healthy
production_gate: approved-by-owner | pendingproduction_gate=pending 时可以继续修复与验证,但不能把技术恢复自动升级成业务批准。
上一节:自动故障转移的保护条件 · 返回本章目录 · 下一节:旧主重加入与集群重建 · 查看全书目录 · 查看索引中心