20.5 切换、故障转移与重加入
角色变化不是一个动作,而是一条状态机:
planned switchover 与 unplanned failover 经过其中不同的路径,不能用同一条 成功记录互相代替。
20.5.1 planned switchover 与 unplanned failover
两个动作的前提不同
| 维度 | planned switchover | unplanned failover |
|---|---|---|
| current leader | 健康、可协调 | 可能失联/已死/未知 |
| candidate | 可事前检查并命名 | 在不完整信息中选择 |
| client drain | 可安排 | 通常来不及 |
| WAL catch-up | 可等待 | tail 可能永失 |
| fencing | 正常 demotion 可完成 | 是核心风险 |
| detection | 人工发起,无故障检测 | 必须检测/租约 |
| data-loss risk | 通常可控 | 取决于 sync/lag/failure |
| purpose | 维护、升级、演练 | 恢复故障服务 |
Patroni 官方 patronictl
把 switchover 定位于健康 cluster,把 failover 定位于不健康 cluster,并
明确提醒 failover 可能因 candidate 落后而丢数据。
planned switchover preflight
最低清单:
本章 executable 还固定:
若 topology 与合同不一致,拒绝,而不是“选当前看起来最合适的”。
命令是 mutation
正式底层动作:
--force 只跳过 CLI 交互;它不是“强制安全”。脚本之所以可以用,是因为
外层已有:
生产 runbook 是否允许 --force,要由审批与自动化设计决定。
failover 需要更严格的 stop conditions
在 manual failover 前:
如果旧主状态 unknown,最快的安全动作常是先冻结写,而不是立即 promote。
automatic failover 也需要演练
配置了 Patroni 不代表路径已验证。要测:
并覆盖 process、host、network、DCS 等不同故障。一次 systemctl stop postgresql 只覆盖其中一个很温和的分支。
回退不是 timeline 倒退
本章“恢复基线”含义:
实际历史:
第二次 switchover 没有回到 timeline 5,也不应删除 timeline history。 角色布局恢复,历史继续前进。
planned 结果的正确表述
可以说:
不能说:
20.5.2 端点切换、客户端恢复与只读窗口
role 变化不会迁移现有 TCP session
promotion 后:
不代表:
客户端可能经历:
- connection reset;
- transaction aborted;
- pool 中旧连接失效;
- DNS/VIP/cache 尚未更新;
- HAProxy health check 尚在 rise/fall window;
- driver backoff;
- application circuit breaker;
- in-flight commit outcome unknown。
所以 client RTO 通常晚于 control-plane stable。
stable endpoint
应用应连接 service identity,而不是把当前 primary IP 写死。
Pigsty 默认服务:
| service | port | 默认语义 |
|---|---|---|
| primary | 5433 | HAProxy → current primary pool |
| replica | 5434 | read-only replica pool |
| default | 5436 | current primary direct PostgreSQL |
| offline | 5438 | offline/OLAP route |
正式 probe 使用:
任意成员的 HAProxy 都能根据 Patroni /primary health 把新连接送到当前
primary;本次选一个固定 service host,避免 DNS/VIP 额外变量。
target_session_attrs=read-write
libpq 可以在连接后确认目标接受 read-write transaction。它能避免把连接 留在 recovery/read-only 节点,但不替代:
它是 client-side sanity check,不是 election protocol。
健康检查窗口
服务切换时间含:
Pigsty 当前默认 service 示例会用 Patroni REST /primary,HAProxy 还可在
backend marked down 时关闭 session。准确配置应查看当前 render 后的
HAProxy,而不只照文档默认。
读服务的降级语义
replica service 可继续提供只读,但要回答:
Pigsty default replica service 通常:
业务必须知道 fallback,否则故障时 primary 可能同时承受全部写与回退读。
连接重试与业务重试
分三层:
三者不能混成 driver 的无限 retry。
安全结构:
具体业务必须保存状态和结果,不能只靠本章 synthetic table。
outcome unknown
当客户端在发送后收到 network error:
本章 probe 故意把所有异常保守记为 unknown,然后查表。正式运行:
另一次运行 unknown count 可能不同,甚至可能出现 committed。正确性来自 reconciliation,不来自“通常不会”。
sampled write gap
probe 每约 0.2 秒尝试一次。保守 gap:
正式:
为何几个数不同:
- CLI return 早于完整 topology stable;
- acknowledged event 受 probe interval 影响;
- reconnect/HAProxy/PgBouncer 影响 client;
- conservative metric 刻意使用 stable boundary。
TLS 例外
沙箱外部 port 5433 不接受 TLS,service file 使用:
这只允许本地实验继续,形成 EX20-CLIENT-PROXY-NO-TLS。生产 connection
identity、TLS verification 与 secret rotation 在第 23 章完成,不能复制
这个选择。
20.5.3 pg_rewind、重建与时间线验证
旧 primary 为什么不能直接 start
failover 后:
把旧 primary 直接作为 standby 指向新 primary,不能自动擦掉分叉块。需要 让它的数据目录重新成为 chosen history 的一致副本。
路径:
pg_rewind 做什么
pg_rewind
比较 source 与 target timeline history,找到 divergence point,把 target
中发生变化的 relation block 和必要文件对齐到 source。
典型角色:
不要把方向写反。
前提
target 需要:
还要有足够 WAL 到 divergence point,或可从 archive 取回。
本章捕获:
它们证明前提意图,不证明某次 unplanned divergence rewind 已执行成功。 本章 healthy switchover 由 Patroni 正常 demote/rejoin,没有把手工 rewind 作为正式动作。
rewind 不是无风险修复
官方文档警告:若 pg_rewind 中途失败,target data directory 很可能不再
可恢复,推荐重新 base backup。
因此:
它还会复制 source 的配置文件;重新作为 standby 前要检查 recovery 与 节点特有配置,避免再次启动为错误角色。
rewind 与 rebuild 的选择
| 条件 | 倾向 |
|---|---|
| 大库、小分叉、前提/WAL完整 | rewind |
| target integrity 可疑 | rebuild |
| rewind 失败 | rebuild |
| 缺失 divergence WAL 且 archive 无 | rebuild |
| 节点需要顺便换盘/版本 | rebuild |
| source authority 不清 | 两者都停止 |
“rewind 更快”不能压过 lineage safety。
rejoin acceptance
旧 member 重新加入后检查:
如果只是 systemctl 变绿,还没有完成。
restore redundancy
failover 后服务可能恢复,但 resilience 降级:
incident completion 应区分:
不要在“新主可写”时过早关 incident。
时间线验证
本章正式 sequence:
同时每 phase:
pg-test-3 checkpoint timeline 最终仍为 3,不阻止其在 Patroni timeline 7
上 streaming;详见 20.2.2。
emergency restore 只在单一安全状态触发
本章 drill.py 若 forward 后出错,只会在确认:
时尝试切回 pg-test-1。若 topology ambiguous,它不会猜。自动 cleanup
不得为了“恢复初始状态”制造第二次错误历史。
切换状态机检查表
小结
权威参考
上一节:选主、DCS 与防脑裂 · 返回本章目录 · 下一节:交付并观察 HA 集群 · 查看全书目录 · 查看索引中心