PostgreSQL 14 EOL 迁移指南:升级到 17/18 的停机、验证与回滚
更新日期:2026-08-30
PostgreSQL 14 不是“还能不能继续跑”的问题,而是“能否在停止安全更新前完成一次可验证的迁移”。PostgreSQL 官方版本策略显示:14.24 是当前 14 系列小版本,整个 14 系列将在 2026 年 11 月 12 日结束支持。届时数据库不会自动停止,但社区不再为它发布 bug 与安全修复。
如果生产仍在 14.x,现在应先升级到最新的 14.x 小版本降低已知风险,同时启动大版本迁移。不要把“小版本更新”和“大版本迁移”混成一次临时维护:前者通常不需要 dump/restore,后者会改变系统目录和二进制兼容边界,必须单独演练。
本文给出从 PostgreSQL 14 迁往 17 或 18 的决策、盘点、三种迁移路线、上线门禁和回滚方法。示例假设自建 Linux 集群;RDS、Cloud SQL、Azure Database、Supabase、Neon 等托管服务应优先使用供应商正式升级流程,不要在供应商管理的数据目录里直接执行 pg_upgrade。
先选目标版本,不要只选“最新”
截至 2026-08-30,PostgreSQL 官方列出的受支持版本和当前小版本为:
| 大版本 | 当前小版本 | 最终支持日期 |
|---|---|---|
| 18 | 18.6 | 2030-11-14 |
| 17 | 17.11 | 2029-11-08 |
| 16 | 16.15 | 2028-11-09 |
| 15 | 15.19 | 2027-11-11 |
| 14 | 14.24 | 2026-11-12 |
新目标通常优先评估 PostgreSQL 18,因为支持窗口最长;但“能启动”不等于“可上线”。如果云厂商、备份代理、连接池或关键扩展还没有通过 18 的认证,17 可能是更稳妥的阶段目标。选择前至少确认:
- 云平台和 Linux 发行版是否正式支持目标 major。
- postgis、timescaledb、pg_cron、pgaudit、向量扩展等是否有目标版本构建。
- ORM、驱动、连接池、CDC 和备份工具是否在支持矩阵内。
- 目标版本是否改变查询计划、默认参数或应用依赖的弃用行为。
- 团队能否在目标版本的支持期内减少下一次迁移次数。
不要为了省一次演练先迁到 PostgreSQL 15:它只比 14 多约一年官方支持。也不要在文章发布数月后照抄 18.6;执行当天应再次查看官方版本页并安装目标 major 的最新小版本。
迁移前盘点:先知道自己拥有什么
在生产只读执行下面的查询,把结果保存到变更单。它们不替代监控,但能快速暴露扩展、编码、排序规则、复制槽和大对象等关键边界。
SELECT version();
SHOW server_version;
SHOW server_encoding;
SHOW lc_collate;
SHOW lc_ctype;
SELECT datname,
pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
WHERE datallowconn
ORDER BY pg_database_size(datname) DESC;
SELECT extname, extversion
FROM pg_extension
ORDER BY extname;
SELECT slot_name, slot_type, active, restart_lsn
FROM pg_replication_slots
ORDER BY slot_name;
SELECT count(*) AS large_object_count
FROM pg_largeobject_metadata;
还要从应用侧收集峰值连接数、TPS、写入速率、最长事务、慢查询、复制延迟、数据库和 WAL 增长率。若准备使用逻辑复制,应检查每张需要 UPDATE/DELETE 的发布表是否有合适的主键或 replica identity;没有主键时直接进入切换窗口,通常会把性能问题留到最危险的时刻。
建议把资产分成四张清单:
- 数据对象:database、schema、table、partition、sequence、large object、materialized view。
- 集群对象:role、tablespace、extension、publication/subscription、replication slot。
- 外部依赖:连接池、备份、CDC、监控、定时任务、只读副本。
- 行为基线:核心 SQL 结果、执行计划、延迟、错误率、业务对账数字。
三条迁移路线怎么选
路线一:dump/restore,最容易理解
逻辑导出再恢复最便于跨主机、跨架构和重建干净集群,代价是数据量越大,停写和恢复时间越长。custom 与 directory archive 都能由 pg_restore 选择性恢复;只有 directory 格式支持并行 dump。
先导出集群级对象,再导出每个业务数据库:
set -euo pipefail
backup_dir=/srv/backups/pg14-migration
install -d -m 0700 "$backup_dir"
pg_dumpall \
--host=127.0.0.1 \
--port=5432 \
--username=postgres \
--globals-only \
> "$backup_dir/globals.sql"
pg_dump \
--host=127.0.0.1 \
--port=5432 \
--username=postgres \
--format=directory \
--jobs=4 \
--file="$backup_dir/app.dump" \
app
pg_dump 成功退出只证明导出过程没有报告错误。必须在隔离的目标版本实例中恢复,并运行 schema、行数、约束和业务对账。并行 dump 会使用 jobs + 1 条连接,也会增加源库负载,不能未经压测把 --jobs 改成 CPU 核数后直接在高峰运行。
恢复前先人工审查 globals.sql。新集群已经有 bootstrap superuser,导出文件可能包含同名 role;tablespace 路径也可能已经改变。应把确认过的 role、grant 与 tablespace 语句保存为 globals-reviewed.sql,不要对目标集群盲目执行整个文件。
恢复示例应在空目标集群执行,并使用目标版本的客户端工具。ON_ERROR_STOP 确保第一条 SQL 错误就停止,而不是带着不完整的 role 或权限继续:
set -euo pipefail
psql -X --set=ON_ERROR_STOP=on \
--host=127.0.0.1 --port=55432 --username=postgres \
--dbname=postgres \
--file=/srv/backups/pg14-migration/globals-reviewed.sql
createdb --host=127.0.0.1 --port=55432 --username=postgres \
--template=template0 app
pg_restore \
--host=127.0.0.1 \
--port=55432 \
--username=postgres \
--dbname=app \
--jobs=4 \
--exit-on-error \
/srv/backups/pg14-migration/app.dump
创建目标 database 时还应按源库清单显式核对 encoding、locale provider、collation 与 ctype。上面的短命令只适用于目标 cluster 已用兼容 locale 初始化的情况,不能用默认值掩盖排序规则变化。
物理拷贝 PostgreSQL 14 的 data directory 不是跨 major 备份方案。官方明确要求跨大版本使用逻辑备份、pg_upgrade 或复制迁移;不能把旧数据目录挂到 PostgreSQL 18 后期待自动转换。
路线二:pg_upgrade,停机可控
pg_upgrade 适合同机或可搬运物理数据的集群,通常比 dump/restore 快。先安装目标版本二进制和兼容扩展,初始化全新的目标 data directory,然后使用目标版本的 pg_upgrade 执行检查:
/usr/lib/postgresql/18/bin/pg_upgrade \
--check \
--old-bindir=/usr/lib/postgresql/14/bin \
--new-bindir=/usr/lib/postgresql/18/bin \
--old-datadir=/var/lib/postgresql/14/main \
--new-datadir=/var/lib/postgresql/18/main
如果正式迁移计划使用 --link、--clone 或其他传输模式,检查时也必须带同一个模式参数,因为官方会执行模式特有的兼容检查。
默认复制模式占更多磁盘,但旧集群数据保持独立,回滚语义最清楚。支持 reflink 的文件系统可评估 --clone,兼顾速度与旧数据独立性。--link 虽快,却共享数据文件:新集群一旦启动并写入,旧集群就不再安全,回滚只能依赖备份。PostgreSQL 18 的 --swap 可能更快,但从文件传输阶段开始会破坏性修改旧集群,不应作为第一次迁移的默认选项。
生产不要使用 --no-sync。它跳过落盘等待,操作系统崩溃时可能留下损坏的数据目录,只适合可丢弃的演练环境。
路线三:逻辑复制,压缩停写窗口
内置逻辑复制支持跨 major,把 PostgreSQL 14 作为 publisher、目标版本作为 subscriber。完成初始复制并追平延迟后,短暂停写、同步最后增量,再切换连接。官方文档指出,这类 switchover 可以把数据库停机压缩到数秒,但这不是“零工作量零停机”。
逻辑复制当前不会复制:
- schema 定义和 DDL;应先用 schema-only dump 建目标结构,并手工保持两端 DDL 顺序。
- sequence 当前值;切换前必须冻结写入并校准所有 sequence。
- large objects;使用它们的系统需要换迁移方式或单独搬运。
- view、materialized view、foreign table 等非普通表关系。
此外,目标表结构不兼容时复制会停住;分区表、generated column、replica identity 和 trigger 行为都应按实际 schema 演练。切换步骤至少包括:停止写入口、等待 subscription lag 清零、同步 sequence、业务对账、切换连接、观察目标库。旧库在回滚期保持只读,不能让新旧两端同时接受独立写入。
一次可信演练应验证什么
同一份生产快照至少完整演练一次,记录每一步用时,而不是只跑 pg_upgrade --check。
数据完整性
- database、schema、table、partition、index、constraint、extension 数量一致。
- 关键表总数与按租户/日期分组的业务对账一致。
- role、owner、grant、default privilege 与连接权限符合预期。
- sequence 的下一值不会与现有主键冲突。
- publication、subscription、slot、定时任务按新拓扑重建,没有双重执行。
查询与应用兼容
- 在目标版本重放核心读写、报表、全文检索和长事务。
- 比较高频 SQL 的 EXPLAIN (ANALYZE, BUFFERS),重点看 join 顺序、估算偏差和磁盘 spill。
- 使用与生产一致的驱动、ORM、连接池和 TLS 设置跑回归测试。
- 验证备份、恢复、监控、告警、CDC 和只读副本,而不只是首页返回 200。
statistics 与 collation
大版本迁移后查询统计信息可能需要重新生成。按 pg_upgrade 输出执行其分析脚本,或使用:
vacuumdb --all --analyze-in-stages --host=127.0.0.1 --port=55432
操作系统或 ICU 版本变化还可能产生 collation version mismatch。官方要求先重建依赖该排序规则的对象,例如执行受控的 REINDEX,再运行 ALTER COLLATION ... REFRESH VERSION 或 ALTER DATABASE ... REFRESH COLLATION VERSION。只刷新版本号会隐藏警告,却不能修复排序定义变化导致的索引风险。
生产切换 Runbook
建议把切换写成可以逐项签字的 Runbook:
- 冻结 DDL,确认演练使用的 schema 与生产一致。
- 核验最近一次备份,并在隔离实例证明它能恢复。
- 宣布维护窗口,降低任务队列和长事务,记录源库 LSN 与关键指标。
- 停止所有写入口,包括 API、后台、cron、queue consumer 和人工脚本。
- 确认没有遗漏写入,执行最终同步或正式 pg_upgrade。
- 在目标库完成 statistics、extension、sequence 与权限检查。
- 先开放内部 canary,跑最小读写、事务、搜索、上传和后台任务。
- 分批切换连接,持续观察错误率、锁等待、复制、CPU、I/O 和慢查询。
- 达到观察窗口前,不删除 PostgreSQL 14 集群、备份或迁移日志。
应用连接最好通过稳定的服务发现、代理或 secret 引用切换,而不是同时修改大量实例。连接池必须主动 drain 和重建,否则旧连接可能继续写源库。
回滚不是“把 DNS 改回去”
真正的回滚取决于目标库是否已经接受新写入:
- canary 前失败:目标库没有业务写入,可恢复 PostgreSQL 14 服务并重新开放应用。
- 切换后但仍全局只读:可以把连接切回仍保持一致的旧库。
- 目标库已经接受写入:直接切回会丢失这些写入。必须提前设计反向同步、事务补偿,或从备份加增量日志恢复。
- pg_upgrade --link 后启动过新集群:旧 data directory 不再安全,必须从独立备份恢复。
- pg_upgrade --swap 已进入破坏阶段:同样依赖独立备份。
所以回滚门槛应在变更前定义:最多允许多少错误、延迟、对账差异;由谁决定停止;新写入如何保存。没有写入处置方案的“回滚按钮”只是一张心理安慰图。
迁移完成后的收尾
完成切换后至少观察一个完整业务周期,再处理旧资源:
- 更新 CMDB、镜像、IaC、监控、备份和灾备文档里的 major/port/路径。
- 确认目标库正在运行部署日最新 minor,并订阅 PostgreSQL 安全公告。
- 做一次目标版本的备份和隔离恢复,证明备份链已切换。
- 移除废弃 replication slot、旧订阅和临时防火墙规则。
- 只有在回滚期结束、负责人批准后才归档或删除旧集群。
PostgreSQL 14 EOL 迁移的价值不只在于版本号。一次做好资产盘点、恢复验证、切换门禁和回滚数据路径,下一次 major 升级才会从“数据库手术”变成可重复的常规变更。历史安全更新背景也可参考本站的 PostgreSQL 10.2 安全修复记录,但版本与命令应始终以当前官方文档为准。
