理解并执行PostgreSQL故障转移与计划切换场景

了解何时使用PostgreSQL计划切换或故障转移,如何检查副本安全性,以及如何在HA事件期间避免脑裂。

理解并执行PostgreSQL故障转移与计划切换场景

PostgreSQL故障转移与计划切换之间的区别并非学术问题,尤其是当你手持寻呼机时。计划切换是有计划的:你仍然有一个健康的主节点,可以排空写入,并选择最佳时机将可写角色移至备用节点。故障转移则是在主节点宕机、不可达或不安全继续服务时采取的措施。

这一区别改变了所有操作。在计划切换期间,你的主要任务是耐心:在提升前证明备用节点已追上进度。在故障转移期间,你的主要任务是遏制:确保在备用节点提升后,旧主节点不能再接受写入。大多数丑陋的PostgreSQL HA事故都源于匆忙执行这两个任务之一。

复制基础:HA的基石

PostgreSQL高可用性建立在流复制之上,其中一台服务器作为主节点(或主服务器),一台或多台服务器作为备用节点(或副本)。主节点将预写日志(WAL)记录流式传输到备用节点以保持同步。

为了有效管理这些角色,主节点和副本节点都需要特定的配置设置:

关键配置设置

这些设置控制复制操作以及节点如何相互识别:

  • wal_level:必须在主节点上设置为replica或更高(如果使用需要逻辑解码的工具,理想情况下设置为logical)。
  • max_wal_senders:定义最大并发WAL发送连接数。根据所有物理备用节点、基础备份以及可能同时连接的复制工具进行大小调整。
  • hot_standby:必须在备用服务器的postgresql.conf中设置为on,以允许复制期间的只读查询。
  • synchronous_commit:控制事务何时被确认。它仅在正确配置同步复制时提供更强的持久性;单独使用时,它不会使备用节点保持最新。
  • primary_conninfo:在备用节点上设置,详细说明连接到当前主节点的连接信息(主机、端口、用户、密码)。

最佳实践: 在PostgreSQL前面放置一个稳定的端点,例如HAProxy、虚拟IP后的PgBouncer、服务发现记录或平台的服务抽象。应用程序不应需要知道今天哪个节点是主节点。

计划切换:有计划的过渡

计划切换是一个受控、优雅的过程,其中主动主节点被有意退役,并提升指定的备用节点以取代其位置。此过程通常用于计划维护、版本升级或硬件更换。

受控计划切换的步骤

计划切换的目标是通过在提升前等待所有进行中的事务被复制,确保零数据丢失

  1. 停止当前主节点上的写入: 第一步是防止在当前主节点上提交任何新事务。这通常通过设置default_transaction_read_only = on或临时关闭客户端连接来实现。
  2. 等待复制追赶: 确保指定的备用节点已接收并应用了主节点的所有剩余WAL记录。您可以在主节点上使用pg_stat_replication检查复制延迟,或通过检查备用节点的恢复状态。
  3. 启动备用节点提升: 执行命令将选定的备用服务器提升为主节点角色。具体命令取决于使用的管理工具(例如,pg_ctl promote或集群管理器命令)。
  4. 重新配置旧主节点: 一旦备用节点成功提升,旧主节点必须重新配置为跟随主节点作为备用节点。这涉及更新其primary_conninfo
  5. 重定向应用程序: 更新负载均衡器或连接池器以将流量定向到新的主服务器。

一个实用的计划切换清单通常看起来更平常而非戏剧性。宣布短暂的写入暂停,停止持续写入的后台工作,将应用程序置于维护模式或排空写入器池,然后检查复制位置。在旧主节点上,pg_stat_replication显示备用节点是否已接收并刷新WAL。在备用节点上,pg_last_wal_receive_lsn()pg_last_wal_replay_lsn()帮助您查看WAL是仅仅到达还是实际已被重放。

不要仅仅因为备用节点已连接就提升它。如果备用节点正在重放大型事务、等待磁盘I/O或在网络暂停后恢复,它可能已连接但仍然落后几秒或几分钟。对于计划切换,您希望在提升前重放已赶上。如果备用节点上运行只读会话,还要检查长时间运行的查询是否延迟了WAL重放。

提升后,直接测试角色:

SELECT pg_is_in_recovery();

提升的节点应返回false。降级的节点在重建或重新配置为备用节点后,应返回true

应用程序端同样需要关注。在计划切换前,了解客户端如何发现写入器。如果它们连接到DNS名称,了解DNS TTL以及客户端是否缓存地址超过预期时间。如果它们通过PgBouncer连接,决定是否需要暂停池、重新加载或重启。如果使用HAProxy,确保健康检查测试可写状态,而不仅仅是端口5432是否打开。运行PostgreSQL的备用节点不是有效的写入目标。

我还喜欢写下回滚点。在提升前,您通常可以停止、在旧主节点上重新打开写入,并稍后重试。提升后,回滚变成一个新的角色更改,而不是简单的撤销。这并不意味着提升是危险的;而是意味着操作员应该知道自己处于哪一侧。

故障转移:紧急响应

故障转移是一个立即的、反应性的过程,在当前主服务器意外故障(例如,硬件崩溃、网络分区、软件错误)且无法快速恢复时触发。

故障转移固有地带有更高的数据丢失风险,因为无法保证最后几个已提交的事务在故障发生前有时间流式传输到备用节点。

执行紧急故障转移

故障转移过程旨在速度和恢复,通常利用专门的工具来自动化提升。

  1. 确定旧主节点的健康状况: 验证原始主节点确实不可用,而不仅仅是经历瞬态网络问题(这可以防止危险的‘脑裂’场景)。
  2. 选择最佳备用节点: 选择复制延迟最小的备用节点(在WAL流中最靠前的节点)。
  3. 提升备用节点: 立即使用提升命令(pg_ctl promote)提升选定的备用节点。
  4. 处理数据丢失(如有必要): 如果集群使用异步复制,则可能需要在故障主节点上丢失的数据进行手动协调或直接接受,具体取决于应用程序的容忍度。
  5. 重新配置原主节点: 一旦原始主节点恢复,必须清理、重新初始化(通常需要从新主节点进行基础备份),并配置为跟随新主节点。

故障转移的难点不是输入pg_ctl promote。难点在于决定旧主节点必须被视为不安全,直到证明并非如此。如果旧主节点仍在运行但与应用程序或备用节点断开连接,您可能会遇到脑裂:两个可写的PostgreSQL服务器接受不同的历史记录。一旦发生这种情况,PostgreSQL不会为您合并历史记录。您将面临手动数据协调或从备份恢复一侧。

在真实事件中,我宁愿多花一分钟隔离旧主节点,也不愿第二天解释为什么两个订单记录不一致。隔离可能意味着关闭旧VM的电源、断开其网络接口、禁用写入器端点,或使用云/提供商机制保证旧主机无法接收写入。具体方法取决于您的基础设施,但要求很简单:在客户端写入新主节点之前,旧主节点必须不能被这些客户端写入。

故障转移后,预计会有清理工作。如果旧主节点恢复,不要随意将其指向新主节点并希望它赶上。它可能包含属于旧时间线的WAL。在许多环境中,最安全的路径是如果满足先决条件则使用pg_rewind,否则从新主节点进行全新的基础备份。

在紧急工作中经常被忽略的一个细节是复制槽的故事。如果旧主节点为备用节点使用了物理复制槽,除非您的HA工具管理它们,否则这些槽不会神奇地随提升的备用节点移动。故障转移后,检查新主节点是否具有您的幸存备用节点所需的槽,并检查是否有任何废弃的槽永远保留WAL。一个被遗忘的槽可能在可见中断结束后几小时内填满磁盘。

对备份使用同样的纪律。一旦集群有了新主节点,确认备份和WAL归档现在跟随该主节点。一个恢复服务但悄悄停止备份的故障转移只是半个恢复。

安全提升工具:Repmgr vs. Patroni

虽然使用pg_ctl手动提升是可能的,但健壮的HA环境依赖于专用工具来管理故障转移和计划切换所需的复杂编排,自动处理配置更改和集群状态管理。

Repmgr(复制管理器)

repmgr是一个轻量级工具,帮助注册节点、监控复制并执行受控的角色更改。具体命令取决于版本和集群布局,但常见模式是:

  • 计划切换: 在确认复制健康后,从应成为主节点的备用节点运行计划的repmgr standby switchover
  • 故障转移: 仅当理解并测试了隔离和见证/仲裁行为时,才让repmgrd执行自动故障转移。

Patroni

Patroni利用分布式共识存储(如etcd、ZooKeeper或Consul)管理集群状态,在检测到故障时自动选举新主节点。Patroni通过API调用或Kubernetes操作器在很大程度上自动化了计划切换和故障转移,大大减少了手动干预。

使用Patroni的示例(概念性提升命令):

# 通过Patroni的REST API触发计划切换
curl -X POST http://patroni-api-endpoint/switchover -H "Content-Type: application/json" -d '{"target": "standby_node_name"}'

关于脑裂的警告: 自动故障转移期间最大的危险是‘脑裂’场景,即由于网络分区,两个节点错误地认为自己是主节点。像Patroni这样的工具使用仲裁机制缓解此问题,而手动设置则需要严格的隔离机制(如电源控制)以确保只有一个主节点存在。

差异总结

特性 计划切换(有计划) 故障转移(紧急)
触发条件 维护、升级、管理选择 主节点故障(崩溃、中断)
数据丢失风险 接近零(如果时机恰当) 中到高(取决于复制模式)
停机时间预期 短暂、受控的停机 立即、反应性的停机
准备 需要事先协调和WAL同步确认 需要立即行动并依赖备用节点健康

一个可适应的小型运行手册

对于计划切换,一个紧凑的运行手册可能如下所示:

  1. 确认选定的备用节点健康且正在重放WAL。
  2. 暂停应用程序写入和后台作业。
  3. 确认复制重放已赶上。
  4. 通过HA工具提升备用节点。
  5. 移动写入器端点。
  6. 确认新主节点上pg_is_in_recovery()false
  7. 将旧主节点重建或回滚为备用节点。
  8. 恢复写入并监控错误、复制和连接计数。

对于故障转移,顺序改变:

  1. 确认主节点已故障或不安全。
  2. 隔离旧主节点。
  3. 选择最先进的备用节点。
  4. 通过HA工具提升它。
  5. 一次性移动写入器端点。
  6. 确认新主节点上的写入正常工作。
  7. 验证副本、槽、备份和WAL归档。
  8. 仅通过回滚或重建重新引入旧主节点。

命令因工具而异,但安全属性不变。一个可写的主节点、已知的复制状态、经过测试的客户端路由以及一种干净的方式将故障节点带回。

在信任任何HA设计之前,在非生产环境中演练两条路径。计划切换演练应证明应用程序干净地重新连接、旧主节点可以再次成为备用节点,并且监控跟随新角色。故障转移演练应证明更严格的事情:故障主节点被隔离、选择提升的备用节点是最佳可用候选、应用程序写入器端点移动一次,并且旧主节点无法在没有回滚或重建的情况下重新加入。

最安全的PostgreSQL HA团队将故障转移视为经过测试的操作工作流程,而不是在中断期间输入的英勇命令。