跳至内容

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 Patroni

leader key 是协调事实,不是“卡住的锁文件”。删除它会触发新的 leader race,却不会 自动停止旧主;如果旧主仍写,删除 key 正好制造双主窗口。

先保护:

  1. 当前 SQL 角色和客户端写入口;
  2. leader lock、revision、member 与 failsafe 内容;
  3. 每个 Patroni 的 REST 角色与可达性;
  4. DCS member/quorum 与 auth 状态;
  5. 旧主 fence 能力;
  6. 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 恢复只说明控制面重新可读写,数据库可能已经有 两个分支或有成员保留陈旧角色。

四层互证表

唯一主库应看到异常例子
DCSone valid leader lockno lock / stale identity
Patroni RESTone primary with lock, replicas elsewheretwo primaries / unknown
SQLaccepted node recovery=false,followers=trueDCS leader SQL 仍 recovery
servicewrite health only points accepted primaryold 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/patroni

SQL:

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 | pending

production_gate=pending 时可以继续修复与验证,但不能把技术恢复自动升级成业务批准。


上一节:自动故障转移的保护条件 · 返回本章目录 · 下一节:旧主重加入与集群重建 · 查看全书目录 · 查看索引中心

最后更新于