升级 PostgreSQL 大小版本

版本升级:小版本滚动升级、大版本迁移、扩展升级

快速上手

PostgreSQL 版本升级分为两种类型:小版本升级大版本升级,两者的风险和复杂度差异很大。

类型示例停机时间数据兼容性风险等级
小版本升级17.2 → 17.3秒级(滚动重启)完全兼容
大版本升级17 → 18分钟级需要升级数据目录
# 滚动升级:先从库后主库
ansible <cls> -b -a 'yum upgrade -y postgresql17*'
pg restart --role replica --force <cls>
pg switchover <cls>
pg restart <cls> <old-primary> --force
# 推荐:逻辑复制迁移
bin/pgsql-add pg-new              # 创建新版本集群
# 配置逻辑复制同步数据...
# 切换流量到新集群
ansible <cls> -b -a 'yum upgrade -y postgis36_17*'
psql -c 'ALTER EXTENSION postgis UPDATE;'

关于在线迁移的详细流程,请参考 在线迁移 文档。

操作说明风险
小版本升级更新软件包,滚动重启
小版本降级回退到之前的小版本
大版本升级逻辑复制或 pg_upgrade
扩展升级升级扩展软件包和扩展对象

小版本升级

小版本升级(如 17.2 → 17.3)是最常见的升级场景,通常用于应用安全补丁和 Bug 修复。数据目录完全兼容,通过滚动重启即可完成。

升级策略:推荐采用 滚动升级 方式:先升级从库,再通过主从切换升级原主库,最小化服务中断。

1. 更新软件仓库 → 2. 升级从库软件包 → 3. 重启从库
4. 主从切换 → 5. 升级原主库软件包 → 6. 重启原主库

步骤一:准备软件包

确保本地软件仓库中有最新版本的 PostgreSQL 包,并刷新节点缓存:

cd ~/pigsty
./infra.yml -t repo_upstream      # 添加上游仓库(需要互联网)
./infra.yml -t repo_build         # 重建本地仓库
ansible <cls> -b -a 'yum clean all'
ansible <cls> -b -a 'yum makecache'
ansible <cls> -b -a 'apt clean'
ansible <cls> -b -a 'apt update'

步骤二:升级从库

在所有从库上升级软件包并验证版本:

ansible <cls> -b -a 'yum upgrade -y postgresql17*'
ansible <cls> -b -a '/usr/pgsql/bin/pg_ctl --version'
ansible <cls> -b -a 'apt install -y postgresql-17'
ansible <cls> -b -a '/usr/lib/postgresql/17/bin/pg_ctl --version'

重启所有从库以应用新版本:

pg restart --role replica --force <cls>

步骤三:切换主库

执行主从切换,将主库角色转移到已升级的从库:

pg switchover <cls>
# 或非交互式:
pg switchover --leader <old-primary> --candidate <new-primary> --scheduled=now --force <cls>

步骤四:升级原主库

原主库现在已降级为从库,升级软件包并重启:

ansible <old-primary-ip> -b -a 'yum upgrade -y postgresql17*'
ansible <old-primary-ip> -b -a 'apt install -y postgresql-17'
pg restart <cls> <old-primary-name> --force

步骤五:验证

确认所有实例版本一致:

pg list <cls>
pg query <cls> -c "SELECT version()"

小版本降级

在极少数情况下(如新版本引入 Bug),可能需要将 PostgreSQL 降级到之前的版本。

步骤一:获取旧版本包

cd ~/pigsty; ./infra.yml -t repo_upstream     # 添加上游仓库
cd /www/pigsty; repotrack postgresql17-*-17.1 # 下载指定版本的包
cd ~/pigsty; ./infra.yml -t repo_create       # 重建仓库元数据
ansible <cls> -b -a 'yum clean all'
ansible <cls> -b -a 'yum makecache'

步骤二:执行降级

ansible <cls> -b -a 'yum downgrade -y postgresql17*'
ansible <cls> -b -a 'apt install -y postgresql-17=17.1*'

步骤三:重启集群

pg restart --force <cls>

大版本升级

大版本升级(如 17 → 18)涉及数据格式变更,需要使用专用工具进行数据迁移。

方式停机时间复杂度适用场景
逻辑复制迁移秒级切换生产环境,要求最小停机
pg_upgrade 原地升级分钟~小时测试环境,数据量较小

逻辑复制迁移

逻辑复制迁移是生产环境大版本升级的推荐方式,核心步骤:

1. 创建新版本目标集群 → 2. 配置逻辑复制同步数据 → 3. 验证数据一致性
4. 切换应用流量到新集群 → 5. 下线旧集群

步骤一:创建新版本集群

pg-meta-new:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta-new
    pg_version: 18                    # 新版本
bin/pgsql-add pg-meta-new

步骤二:配置逻辑复制

-- 源集群(旧版本)主库:创建发布
CREATE PUBLICATION upgrade_pub FOR ALL TABLES;

-- 目标集群(新版本)主库:创建订阅
CREATE SUBSCRIPTION upgrade_sub
  CONNECTION 'host=10.10.10.11 port=5432 dbname=mydb user=replicator password=xxx'
  PUBLICATION upgrade_pub;

步骤三:等待同步完成

-- 目标集群:检查订阅状态
SELECT * FROM pg_stat_subscription;

-- 源集群:检查复制槽 LSN
SELECT slot_name, confirmed_flush_lsn FROM pg_replication_slots;

步骤四:切换流量

确认数据同步完成后:停止应用写入源集群 → 等待最后的数据同步 → 切换应用连接到新集群 → 删除订阅,下线源集群。

-- 目标集群:删除订阅
DROP SUBSCRIPTION upgrade_sub;

详细的迁移流程请参考 在线迁移 文档。

pg_upgrade 原地升级

pg_upgrade 是 PostgreSQL 官方提供的大版本升级工具,适用于测试环境或可接受较长停机时间的场景。

步骤一:安装新版本软件包

./pgsql.yml -l <cls> -t pg_pkg -e pg_version=18

步骤二:停止 Patroni

pg pause <cls>                        # 暂停自动故障转移
systemctl stop patroni                # 停止 Patroni(会停止 PostgreSQL)

步骤三:运行 pg_upgrade

sudo su - postgres
mkdir -p /data/postgres/pg-meta-18/data

# 预检(-c 参数只检查不执行)
/usr/pgsql-18/bin/pg_upgrade \
  -b /usr/pgsql-17/bin -B /usr/pgsql-18/bin \
  -d /data/postgres/pg-meta-17/data \
  -D /data/postgres/pg-meta-18/data \
  -v -c

# 执行升级
/usr/pgsql-18/bin/pg_upgrade \
  -b /usr/pgsql-17/bin -B /usr/pgsql-18/bin \
  -d /data/postgres/pg-meta-17/data \
  -D /data/postgres/pg-meta-18/data \
  --link -j 8 -v

步骤四:更新链接并启动

rm -rf /usr/pgsql && ln -s /usr/pgsql-18 /usr/pgsql
rm -rf /pg && ln -s /data/postgres/pg-meta-18 /pg
# 编辑 /etc/patroni/patroni.yml 更新路径
systemctl start patroni
pg resume <cls>

步骤五:后处理

/usr/pgsql-18/bin/vacuumdb --all --analyze-in-stages
./delete_old_cluster.sh   # pg_upgrade 生成的清理脚本

扩展升级

升级 PostgreSQL 版本时,通常也需要升级相关扩展插件。

升级扩展软件包

ansible <cls> -b -a 'yum upgrade -y postgis36_17 timescaledb-2-postgresql-17* pgvector_17*'
ansible <cls> -b -a 'apt install -y postgresql-17-postgis-3 postgresql-17-pgvector'

升级扩展版本

软件包升级后,在数据库中执行扩展升级:

-- 查看可升级的扩展
SELECT name, installed_version, default_version FROM pg_available_extensions
WHERE installed_version IS NOT NULL AND installed_version <> default_version;

-- 升级扩展
ALTER EXTENSION postgis UPDATE;
ALTER EXTENSION timescaledb UPDATE;
ALTER EXTENSION vector UPDATE;

-- 检查扩展版本
SELECT extname, extversion FROM pg_extension;

注意事项

  1. 备份优先:任何升级操作前都应进行完整备份
  2. 测试验证:先在测试环境验证升级流程
  3. 扩展兼容:确认所有扩展支持目标版本
  4. 回滚预案:准备好回滚方案,特别是大版本升级
  5. 监控观察:升级后密切监控数据库性能和错误日志
  6. 文档记录:记录升级过程中的所有操作和问题

相关文档