PostgreSQL 数据库小版本与大版本升级详解

一、概念定义

PostgreSQL 的版本号自 10 起采用「主版本号.次版本号」两段式(如 16.4),与 10 之前的三段式(如 9.6.3)不同。据此分为两类升级:

升级类型 版本变化 示例 本质
小版本升级(Minor) 同一主版本内的补丁版本变化 16.3 → 16.5 仅修复缺陷与安全问题,不改变磁盘格式、不增删功能、不改默认行为
大版本升级(Major) 主版本号变化 15 → 16 可能改变系统目录、磁盘存储格式、默认参数、SQL 行为,并移除或废弃特性

核心区别:小版本升级只需替换二进制、重启服务 即可完成,兼容性高;大版本升级不能仅替换二进制 ,必须经过数据目录格式转换(如 pg_upgrade)或逻辑重建(逻辑复制 / pg_dump)。

二、作用与适用场景

  • 小版本升级 :用于跟进安全补丁、修复已知缺陷、获得稳定性改进。风险可控,但生产环境可稍作延迟以观察社区反馈,不宜长期滞后。
  • 大版本升级:用于获取新特性与性能提升、延长版本支持周期(老版本 EOL 后不再有小版本补丁)。是升级中复杂度最高、最需要评估的一类。
  • 在线/不停机升级 :当业务无法接受长停机窗口(如数十 TB、数万 TPS 的核心库)时采用,通过逻辑复制等手段把停机时间压缩到分钟级甚至秒级。

三、工作机制与具体步骤

3.1 小版本升级机制与步骤

机制:同一主版本内磁盘格式不变,新二进制可原地读取旧数据目录,因此只需停服务、换二进制、起服务。

步骤:

  1. 确认当前版本与目标版本(如 16.4 → 16.5),阅读对应小版本 release notes。
  2. 全量备份:pg_basebackup + 逻辑备份(pg_dumpall),并验证可恢复。
  3. 停止数据库服务,确认无连接。
  4. 更新安装包(如 yum update postgresql16-server / 二进制替换),只替换同主版本的二进制。
  5. 启动服务,检查日志、版本号、扩展状态。
  6. 验证业务连通性与关键查询。

注意 :小版本升级通常不需要 pg_upgrade,也不需要 initdb。但需警惕极少数小版本会破坏 ABI(例如曾出现过小版本升级导致 TimescaleDB 等扩展出问题的案例),因此涉及第三方扩展时仍需先在测试环境验证。

3.2 大版本升级机制

大版本升级有四类方法:pg_upgrade、逻辑复制、pg_dump/pg_dumpall 逻辑备份重建、物理流复制。主流推荐 pg_upgrade。

pg_upgrade 原理 :对新集群执行 initdb,然后把旧集群的元数据(catalog)导入 新集群,数据文件通过 hard link(--link) 或复制方式复用。因此升级速度与数据量无关,只取决于 catalog 的大小。

三种模式对比:

模式 是否复制数据 停机时间 磁盘占用 回滚
--link(推荐) 硬链接,不复制 分钟级 约 1× 保留旧集群,停新起旧即可,但丢失升级期间的增量写入
--copy 完整复制 与数据量成正比 约 2× 旧集群完好,回滚简单
--copy-file-range 内核态拷贝 较快 约 2× 旧集群完好;系统不支持该调用时会退化为用户态拷贝,CPU/内存开销升高

标准步骤(以 PG14 → PG16 为例):

  1. 备份双保险 :pg_basebackup 全量 + 确认归档连续性 + pg_dumpall 逻辑备份,并试恢复一次验证可用。

  2. 存储快照:对数据目录、WAL、归档、表空间所在文件系统创建快照(如 ZFS snapshot),作为快速回退兜底。

  3. 升级前评估 :逐版本阅读 release notes 的 Migration / 不兼容变更 章节(如 PG12 移除 abstime/reltime),在测试环境做全量回归。

  4. 升级前检查 :梳理枚举类型、扩展版本、public schema 函数、非内部触发器、WITH OIDS 表、自定义后缀运算符等。

  5. 预检演练 :在测试环境执行 pg_upgrade --check,修复全部 ERROR 后 再进入生产窗口:

    bash 复制代码
    sudo -u postgres /usr/pgsql-16/bin/pg_upgrade \
      --old-datadir=/var/lib/pgsql/14/data \
      --new-datadir=/var/lib/pgsql/16/data \
      --old-bindir=/usr/pgsql-14/bin \
      --new-bindir=/usr/pgsql-16/bin \
      --check

    注意:--check 无法穷举所有失败问题,部分隐患只写在 release notes 的不兼容说明里。

  6. 执行升级 (停库后):

    bash 复制代码
    sudo -u postgres /usr/pgsql-16/bin/pg_upgrade \
      --old-datadir=/var/lib/pgsql/14/data \
      --new-datadir=/var/lib/pgsql/16/data \
      --old-bindir=/usr/pgsql-14/bin \
      --new-bindir=/usr/pgsql-16/bin \
      --jobs=4 --link
  7. 重建从库 :物理从库的数据文件需与主库 block 级别一致,必须重建 (或用 rsync --hard-links --size-only 同步)。

  8. 收集统计信息 :pg_upgrade 仅迁移元数据,不迁移统计信息 ,升级后必须手动 ANALYZE(PG18 起 pg_upgrade 支持统计信息导出导入,可免此步):

    bash 复制代码
    vacuumdb --analyze-only --all --jobs 8
  9. 启动验证:检查版本、扩展、复制状态、关键业务 SQL 与执行计划。

3.3 在线升级(不停机 / 少停机)

方案一:逻辑复制升级

原理:新建目标大版本集群,通过逻辑复制(原生逻辑复制或 pglogical)持续同步增量,业务几乎不中断,最后秒级切流。

  • 优点:几乎不停业务,可跨版本。
  • 限制:要求表有主键或唯一键 ;不支持 DDL 与序列当前值同步,需额外做一致性校验;配置复杂。
  • 统计信息处理:可在复制运行期间对目标集群执行 ANALYZE,无需 --analyze-in-stages。

方案二:零停机升级(大型集群)

组合物理复制 + 逻辑复制 + pg_upgrade --link + 连接池 PgBouncer 的 PAUSE/RESUME,核心是 physical2logical 转换 :把物理副本转换为逻辑副本,用 recovery_target_lsn 精确定位复制槽位置,避免逻辑复制从头初始化的巨大开销。

主要阶段:

  1. initdb 建新集群,作为旧集群主库的级联物理复制从节点;

  2. 追平延迟后停新集群节点;

  3. 旧集群主库建发布与逻辑复制槽,记录 LSN:

    sql 复制代码
    CREATE PUBLICATION pub_name FOR ALL TABLES;
    SELECT pg_create_logical_replication_slot('slot_name', 'pgoutput');
  4. 新集群配置 recovery_target_lsn 追到该 LSN 后提升;

  5. 再次停止后执行 pg_upgrade --link,同步副本;

  6. 新集群建订阅追赶旧集群,切换时用 copy_data = false:

    sql 复制代码
    CREATE SUBSCRIPTION sub_name
      CONNECTION 'host=... port=... dbname=...'
      PUBLICATION pub_name
      WITH (copy_data = false);
  7. PgBouncer PAUSE 停流量 → 校验同步 → 切换 → RESUME;可设置反向逻辑复制实现全流程回滚。

方案三:pg_createsubscriber(PG17+)

将物理备库快速转换为逻辑订阅者,用 standby 做大版本升级后快速同步原主库增量,大幅缩短停机窗口 ,PG17 起还支持 --all 一键创建所有对象的订阅。

方案四:逻辑复制槽保留(PG17+)

PG17 之前,逻辑复制环境做大版本升级必须先删除复制槽、升级后重新同步;PG17 起无需删除,简化了流程。

四、相关对象与观察入口

相关工具

工具 用途
pg_upgrade 大版本升级(--check 预检、--link/--copy 模式、--jobs 并行)
pg_dump / pg_dumpall 逻辑备份与跨版本重建式升级
pg_basebackup 升级前物理全量备份
vacuumdb --analyze-only 升级后并行收集统计信息
pg_createsubscriber PG17+ 由物理备库快速创建逻辑订阅

相关系统表 / 视图

对象 用途
pg_extension 查看已安装扩展及版本,避免升级后版本不匹配
pg_proc 查看 public schema 下函数及语言,评估兼容性
pg_type 筛选枚举类型等,确认定义正确迁移
pg_trigger 查看非内部触发器及所属表
pg_publication / pg_subscription 逻辑复制发布/订阅信息
pg_replication_slots 复制槽状态(pg_upgrade 会销毁所有 slot)
pg_stat_replication 复制延迟,切换前确认延迟归零

关键参数

recovery_target_lsn(physical2logical 定位)、default_statistics_target(影响 ANALYZE 开销)、lock_timeout(在线变更时限制锁等待)。

五、常见误区与边界

  1. 升级后忘记 ANALYZE :pg_upgrade 与主流云厂商流程都不会自动执行 ANALYZE,统计信息缺失/过期会导致升级后业务高峰出现严重性能下降甚至宕机。应纳入自动化流程;PG18 起可通过 pg_upgrade 迁移统计信息免除全库 ANALYZE,但那是「升级前快照」,升级后 48 小时内仍应对热表补 ANALYZE。
  2. 逻辑复制槽被销毁 :pg_upgrade 会销毁新集群所有 replication slots,若升级后立即开放写入将导致数据无法同步。正确顺序是:阻断应用写入(仅留复制连接)→ 确认延迟归零 → 订阅端 DROP SUBSCRIPTION → 依次升级订阅端与发布端 → CREATE SUBSCRIPTION ... WITH (copy_data=FALSE) 重建 → 验证 → 重建其他槽 → 恢复流量。
  3. --link 的代价 :硬链接要求新旧数据文件在同一文件系统,回滚虽快但会丢失升级期间的增量写入,且旧数据目录被复用后不可再启动旧集群。
  4. 逻辑复制不支持 DDL 与序列:需人工处理表结构变更与序列当前值,并做一致性校验。
  5. 小版本并非绝对无风险:极少数小版本会破坏 ABI,影响第三方扩展;涉及扩展时应先验证。
  6. 不要跨太多大版本一次升级:跨多个大版本需累积阅读各版本 release notes,工作繁琐且风险叠加,建议定期做小版本升级避免积累。
  7. --check 不等于万无一失:部分失败原因藏在 release notes 的不兼容章节,预检无法穷尽。

六、延伸知识

  • 版本升级方法总览 :pg_upgrade 操作、逻辑复制 / pg_logical、pg_dump / pg_dumpall、物理流复制四类。
  • PG16 起的零停机基础模块 :双活复制、蓝绿部署、零停机大版本升级的基础能力已逐步就绪(部分需扩展如 pgactive 支持)。
  • 回滚体系:物理备份 + 归档 PITR + 逻辑 dump 双保险,配合存储快照实现快速回退。
相关推荐
ao-weilai1 小时前
MySQL数据库:索引
数据库·mysql
shaibdoio2 小时前
瞬维AI落地经验:AI Agent工具调用准确率怎么提
数据库·人工智能·oracle
NPE~2 小时前
CMDB科普:配置管理数据库——运维相关
运维·数据库·科普·cmdb·配置管理数据库
Highcharts.js2 小时前
动态数据可视化架构:Highcharts + PHP + MySQL 从数据库到数据渲染
数据库·mysql·php·开发文档·实时数据·highcharts·图表开发
余槐i2 小时前
WAL 下写并发仍是 1:SQLite 单写者模型实测与绕开方案
数据库·python·性能优化·sqlite·wal
阳光九叶草LXGZXJ10 小时前
达梦数据库-报错-15-列【XXX】长度超出定义
linux·运维·数据库·sql·学习
字节渡客11 小时前
Redis键明明过期了,业务还在读到旧数据
数据库·redis·spring
OnlineProxy13 小时前
亚马逊多账号运营:如何在规避“关联封号”风险的同时实现电商规模化扩张
服务器·数据库·redis
辻弋20115 小时前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑