内容提要
本文介绍Neki数据库系统的计划外故障转移设计:主库P失联时,Admin不单凭自身健康检查判断,而是询问各副本;若仍有副本在流式复制则不切换,仅当至少一个可达副本报告复制中断且无相反证据时才判定P死亡。切换前断开副本连接以防P恢复后重新获得副本,并冻结各副本WAL位置;随后选择已重放最高WAL位置的副本提升为新主库,其余副本可顺利跟随。P被标记为TEARDOWN,保留用于事后分析。
延伸解读
副本视角:故障判定的关键证据
Neki 不依赖 Admin 单方面健康检查,而是询问副本的复制状态。只有当至少一个可达副本报告复制中断且无相反证据时,才判定主库死亡。这避免了网络分区下误切,但若 Admin 与所有副本失联,则无法切换,只能等待。
断开副本连接的双重作用
切换前,Neki 通过修改 primary_conninfo 前缀 // 断开副本与旧主库的连接。这既防止旧主库恢复后重新获得副本确认(在 ANY 1 同步策略下无法提交),又冻结各副本的 WAL 位置,为选择新主库提供稳定依据。
WAL 位置选择与数据丢失风险
新主库优先选择已重放最高接收 WAL 位置的副本,使其余副本能顺利跟随。但 ANY 1 仅保证每个已提交事务至少到达一个副本,若该副本与主库同时故障,事务可能丢失。跨可用区确认可降低此风险,但增加提交延迟。
旧主库的处置:保留而非立即重用
故障切换后,旧主库被标记为 TEARDOWN,不参与流量和复制。与计划内切换不同,Neki 不会自动将其转为新主库的副本,因为它可能含有新主库没有的写入。通常保留其日志和磁盘状态用于事后分析,再决定销毁或重新加入。
Q&A
Neki 在计划外故障转移时,如何判断主库 P 是否真的死亡?
Admin 不会仅凭自身健康检查失败就判定 P 死亡,而是询问各副本。只有当 Admin 无法联系 P,且至少一个可达副本报告复制中断,同时没有其他可达副本提出相反证据时,才将 P 判定为死亡并尝试恢复。
为什么 Neki 不采用租约(lease)机制来判断主库健康?
文章指出,虽然其他高可用系统使用租约(主库上的代理在分布式存储中持有定期续期的键,键过期则认为主库失败),但 Neki 没有采用这种方式,而是通过询问副本来获取证据。文章未详细解释不采用租约的原因。
在计划外故障转移前,Neki 为什么要断开副本与旧主库的连接?
断开副本连接有两个目的:一是防止旧主库 P 意外恢复后重新获得副本,从而避免出现第二个可写主库;二是冻结各副本的 WAL 位置,使每个副本报告的接收位置成为最终值,用于选择新主库。
Neki 如何选择新的主库?依据是什么?
Neki 选择已重放最高 WAL 位置的副本提升为新主库。具体来说,Admin 先寻找已重放至最高接收位置的副本;若没有,则短暂等待后重试;若仍无,则选择接收位置最高的可提升副本,并以重放位置作为次要标准。
计划外故障转移后,旧主库 P 会被如何处理?
Admin 将 P 标记为 TEARDOWN,使其不再服务流量、不参与复制,并停止监控。与计划内切换不同,Neki 不会将 P 转为新主库的副本,因为 P 可能包含新主库上没有的写入。P 通常被保留用于事后分析,之后可销毁、回收或经明确决定重新加入分片。
Neki 如何检测冻结的 Postgres 进程导致的复制中断?
对于冻结的 Postgres 进程,TCP 层仍会响应,连接看似健康。Neki 通过调整 Postgres 复制设置,使用 wal_receiver_timeout 来检测:如果主库几秒内没有发送任何数据,副本会关闭连接并报告复制中断。