导读:本期聚焦于唐振业创作的《pg_upgrade升级失败后如何安全回滚?详细步骤与注意事项》,敬请观看详情。pg_upgrade是PostgreSQL大版本升级的常用工具,但如果升级过程中报错中断或升级后发现应用不兼容,如何安全退回旧版本而不丢数据?本文围绕pg_upgrade的工作原理,讲解升级失败后的回滚思路,包括保留旧数据目录的完整方法、清理新集群残留文件、恢复旧版本服务启动、校验数据一致性等关键步骤,并总结了升级前做备份、使用link模式的注意事项,以及避免回滚失败的常见坑,帮助你在升级出问题时快速恢复业务。

PostgreSQL大版本升级时,很多运维人员会选用pg_upgrade工具,它能在不导出全部数据的情况下完成版本迁移,速度快、停机窗口短。但升级并不总是顺利的,比如磁盘空间不足、新旧版本字符集不匹配、扩展插件在新版本不可用,甚至升级完成后业务方发现新版行为变化导致功能异常,这时候就需要把数据库回滚到旧版本。pg_upgrade本身没有提供undo命令,回滚的核心思路是:只要旧的数据目录还在,直接删掉新集群、重新启动旧集群即可。下面详细介绍具体操作和原理。

pg_upgrade升级失败后如何安全回滚?详细步骤与注意事项

理解pg_upgrade的升级原理才能正确回滚

pg_upgrade的工作方式是在旧数据目录和新数据目录都存在的前提下,对比两个版本的系统目录结构,把旧库的元数据转换写入新目录。如果升级时使用了--link参数,新旧数据目录中的数据文件会通过硬链接共享同一份磁盘空间,从而避免复制数据;如果没加--link,则是完整复制一份新的数据文件。

关键点在于:升级过程中,旧数据目录默认不会被删除或修改(只有system表被重命名为_old结尾),新数据目录是升级的目标。也就是说,只要旧数据目录完整保留,它就是一份可以直接启动的旧版本数据库。回滚之所以简单,正是因为升级操作本质上是单向写入了新目录,而旧目录只是被移动了system catalog的文件名。

需要特别注意的是,如果升级成功后你已经在新集群上运行了业务并写入了新数据,那么这部分数据在旧目录中是不存在的,回滚就意味着放弃这些新增数据。所以回滚决策要尽早做,升级完成后的验证阶段发现问题时回滚成本最低。

升级失败的回滚具体操作步骤

假设旧版本为PostgreSQL 13,新版本为PostgreSQL 16,旧数据目录在/pgdata/13/data,新数据目录在/pgdata/16/data,完整的回滚流程如下。

第一步,确认新旧集群都已停止。使用link模式升级时尤其要保证两个实例都没有进程存活,否则硬链接关系可能导致文件被意外修改。检查进程命令如下:

# 检查是否还有 postgres 进程
ps -ef | grep postgres

# 分别停止两个版本的实例(如果还能启动的话)
/usr/pgsql-13/bin/pg_ctl -D /pgdata/13/data stop -m fast
/usr/pgsql-16/bin/pg_ctl -D /pgdata/16/data stop -m fast

第二步,处理旧数据目录中的system表重命名残留。pg_upgrade运行时会将旧目录中pg_control改名为pg_control.old,并将旧的system catalog文件加上_old后缀(如pg_class_old等,存放在base目录下的各数据库子目录中)。如果升级中断在早中期,这些改名可能只完成了一部分,此时旧集群无法直接启动,需要执行恢复操作把文件名改回去。官方提供的处理方式是删除所有_old结尾的文件,再把pg_control.old改回pg_control:

# 进入旧数据目录,删除重命名后的旧 system catalog 文件
cd /pgdata/13/data/base

# 删除所有以 _old 结尾的文件
find . -name "*_old" -type f -exec rm -f {} \;

# 恢复 pg_control 文件名
mv /pgdata/13/data/global/pg_control.old /pgdata/13/data/global/pg_control

这里务必小心:删除的是带_old后缀的文件,这些是升级开始时被改名隔离的旧system catalog副本,当前有效的catalog文件是不带后缀的。如果不确定目录状态,先做磁盘快照再操作更稳妥。

第三步,删除或移走新数据目录。新目录在回滚后没有价值,直接删除可以释放空间。但如果还想排查升级失败原因,建议先整体移动到备份路径:

# 移走新数据目录以便排查问题
mv /pgdata/16/data /pgdata/16/data_failed_$(date +%Y%m%d)

# 或者确认不再需要时直接删除
# rm -rf /pgdata/16/data

第四步,用旧版本的二进制重新启动旧集群,并验证状态:

# 注意必须使用旧版本的 pg_ctl 启动
/usr/pgsql-13/bin/pg_ctl -D /pgdata/13/data start

# 验证版本和数据
/usr/pgsql-13/bin/psql -d postgres -c "SELECT version();"
/usr/pgsql-13/bin/psql -d postgres -c "SELECT count(*) FROM pg_database;"

最后一步,恢复业务连接。如果之前修改了监听端口、pg_hba.conf或者应用连接串指向了新集群,记得全部改回旧集群的配置。对于使用systemd管理的环境,还要确认服务单元文件指向的是旧版本的bin目录和数据目录。

link模式升级后的回滚注意事项

使用--link参数升级成功后,新旧目录的数据文件通过硬链接指向同一批磁盘块。这种情况下回滚有一个重要的坑:升级成功后旧目录实际上已经被认为是废弃状态,pg_upgrade在升级结束时会提示删除旧目录。此时如果回滚,只要旧目录还没删除,虽然文件被硬链接共享,只要没有在新集群上写入大量数据导致硬链接分裂,旧目录依然可能可用。

但要强调,link模式一旦在新集群上发生过大量写入、更新、删除操作,对应的数据块会因写时复制而与旧目录分道扬镳,旧目录的数据将不再反映最新状态,甚至处于不一致的崩溃恢复点。因此link模式升级后,必须在新集群上执行pg_backup_start之前就决定是否回滚,最稳妥的做法是升级完成、业务验证通过之后再删除旧目录,回滚窗口就维持在这个验证期内。

另外,link模式下新旧目录必须在同一文件系统上。如果回滚时发现旧目录中缺少文件(比如被误删),可以从新目录对应的文件通过硬链接补回,因为文件内容和升级时是完全一样的。这也说明保留新目录一段时间对回滚排查是有帮助的。

如何让回滚更安全:事前准备清单

与其事后补救,不如在升级前就把回滚路径准备好。升级前务必做好以下几件事:

  • 对旧数据目录做完整备份,条件允许时用pg_basebackup或文件系统快照,快照回滚只需要几分钟。
  • 新旧数据目录分别放在独立路径,不要复用同一个目录,避免升级脚本误删旧目录。
  • 记录旧集群的所有配置:postgresql.conf的自定义参数、pg_hba.conf、表空间路径、扩展插件列表,回滚后需要逐一核对。
  • 在升级命令中使用--check参数先做干跑检查,把版本不兼容、locale不一致等会导致失败的问题提前暴露。
  • 规划好回滚决策点和决策人,升级完成后的业务验证项提前列成清单,验证不通过立即触发回滚流程。

还需要提醒一点,升级失败的原因要留档分析。pg_upgrade的输出日志以及新数据目录中的pg_upgrade_output.d文件夹记录了详细过程,把它和失败的新目录一起归档,下次重试升级时可以避开同样的问题。回滚只是应急手段,彻底解决问题后重新规划升级,才能让数据库版本跟上节奏。

pg_upgradePostgreSQL升级数据回滚修改时间:2026-09-11 12:56:41

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0911/54682.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。