Stefan Fercot:pgBackRest 与 PostgreSQL 故障转移:为何 archive_mode 至关重要
内容提要
pgBackRest 要求主库启用 archive_mode 才能备份。级联复制实验中,备库提升后 archive_mode=off,备份报错,archive-mode-check=n 也无法绕过。即使改源码成功备份并恢复,仍缺失时间线切换期间的 WAL 和 .history 文件,无法恢复旧备份。建议提升前设 archive_mode=on,通过重启或受控切换恢复受支持配置。
延伸解读
archive_mode 检查的真正目的
pgBackRest 在备份时强制检查主库的 archive_mode 是否启用,并确认 archive_command 调用了 pgbackrest 子命令。这些检查并非随意限制,而是为了确保备份所依赖的 WAL 归档机制确实在工作。如果主库未归档 WAL,备份可能缺少恢复所需的关键日志,导致备份不可用。因此,archive-mode-check=n 并不能绕过 archive_mode=off 的检查,它只用于处理 archive_mode=always 时可能出现的 WAL 校验和差异问题。
时间线切换期间的 WAL 缺口
实验中,原主库 pg1 处于时间线 1,提升 pg2 后产生时间线 2。由于 pg2 提升时 archive_mode=off,归档仓库中缺失了从时间线 1 末尾到时间线 2 开头之间的 WAL 段,以及记录切换点的 .history 文件。这意味着即使后续备份成功,也无法从仓库中恢复跨越时间线切换的旧备份。备份成功与恢复能力是两回事,缺失的 WAL 和 .history 文件不会因为新备份而补回。
修改源码绕过检查的风险
作者通过修改 pgBackRest 源码去掉了 archive_mode 检查,成功完成了备份并恢复了最新备份。但这只是证明在特定条件下可以工作,并不代表该方案安全可靠。绕过检查后,确保归档一致性的责任转移给了维护修改版的人。一次成功的概念验证无法覆盖所有故障和恢复场景,尤其是涉及旧备份跨时间线恢复时,缺失的 WAL 仍然会导致恢复失败。
提升前应做的准备
建议在提升任何服务器之前,确保 archive_mode=on 且 archive_command 已配置并正常工作。如果暂时没有归档命令,可以在集群生命周期开始时启用 archive_mode,但将 archive_command 留空或设为 /bin/true,这样后续修改 archive_command 只需 reload 而非重启。提升候选节点应提前设置好归档,避免提升后因 archive_mode=off 而无法备份,也避免为启用归档而被迫重启新主库。
Q&A
pgBackRest 备份为什么要求主库必须开启 archive_mode?
pgBackRest 依赖 WAL 归档来保证备份一致性。如果主库 archive_mode=off,备份命令会直接报错“archive_mode must be enabled”,因为缺少归档的 WAL 段,备份无法用于恢复。
备库提升后 archive_mode=off,用 archive-mode-check=n 能绕过备份检查吗?
不能。archive-mode-check=n 只用于跳过对 archive_mode=always 的检查,防止多个归档器写入同一仓库,但它不会绕过“主库必须启用 archive_mode”这一检查。备份仍会失败并报错 [087]。
修改 pgBackRest 源码去掉检查后,备份成功恢复,为什么仍然不可靠?
因为时间线切换期间缺失了 WAL 段和 .history 文件。例如从时间线 1 提升到时间线 2 时,仓库中缺少 000000010000000000000091 到 000000020000000000000093 之间的 WAL,也没有 .history 文件,导致无法恢复旧备份跨越时间线切换。
在 PostgreSQL 故障转移前,应该如何正确配置 archive_mode 和 archive_command?
在提升任何服务器之前,确保 archive_mode=on 且 archive_command 已定义。如果暂时没有归档命令,建议在集群生命周期开始时设置 archive_mode=on 但 archive_command 留空或设为 /bin/true,这样以后修改 archive_command 只需 reload,无需重启。
从备库执行 pgBackRest 备份时,archive_mode 应该设置成什么?
备库应设置 archive_mode=always,并配置 archive_command 调用 pgbackrest archive-push。但注意,如果主库 archive_mode=off,即使备库这样设置,pgBackRest 仍会拒绝备份,因为主库检查不通过。
如果已经用 archive_mode=off 提升了备库,如何恢复到受支持的配置?
推荐通过计划内重启或受控切换(switchover)将 archive_mode 改为 on,并配置好 archive_command。不要依赖修改源码或 archive-mode-check=n 等非受支持方式,因为一次成功的 PoC 不能验证所有故障和恢复场景。