Ubuntu 22.04 系统升级后 PostgreSQL 无法启动:如何解决数据库迁移中的兼容性问题

在我们跨境电商平台的香港数据中心中,有一台来自A5数据的用于核心订单库的物理服务器www.a5idc.com(型号 Dell PowerEdge R650,双路 Intel Xeon Silver 4310,RAM 256 GB,RAID10 SSD),运行 Ubuntu Server 20.04 + PostgreSQL 12。目标是把操作系统升级到 Ubuntu 22.04 来利用最新内核、ZFS 支持和长期支持(LTS)周期延长。

升级过程在测试环境成功后按计划在生产机房执行,但完成 OS 升级重启后 PostgreSQL 无法正常启动,导致业务中断。本文基于这次实践,全量呈现 故障分析、原因排查、解决方案、版本兼容性细节、迁移步骤与评估数据


一、故障表现与初步诊断

故障症状

升级 Ubuntu 20.04 → 22.04 完成后:

  • PostgreSQL 服务启动失败

  • systemctl status postgresql 显示错误

  • 日志报错包含:

    • could not load library "$libdir/postgis-3.so"
    • FATAL: database files are incompatible with server
    • invalid page in block 0 of relation

二、环境与硬件配置

项目 配置
香港服务器型号 Dell PowerEdge R650
CPU 2 × Intel Xeon Silver 4310 (12C/24T, 2.1 GHz)
内存 256 GB DDR4
存储 NVMe SSD × 8 → RAID10 (10 TB 可用)
网络 Broadcom 10 GbE
操作系统(升级前) Ubuntu Server 20.04.6 LTS
PostgreSQL(升级前) v12.11
操作系统(升级后) Ubuntu Server 22.04.3 LTS
PostgreSQL(升级后 apt 安装) v14.8(默认 apt 安装)

三、兼容性问题根因分析

3.1 PostgreSQL 数据目录不兼容

Ubuntu 22.04 默认 PostgreSQL 版本是 14,它不能直接读取 PostgreSQL 12 的数据目录:

复制代码
FATAL: database files are incompatible with server
DETAIL: The database cluster was initialized with ...

原因:PostgreSQL 数据文件格式严格版本绑定,无法跨主版本直接读取。


3.2 扩展模块版本不匹配(如 PostGIS、pg_stat_statements)

例如 PostGIS 库:

复制代码
could not load library "$libdir/postgis-3.so"

Ubuntu 22.04 上的 PostGIS 版本为 3.1,与旧版 2.5 编译方式不同,导致插件无法加载。


四、解决方案总览

核心思路

  1. 不直接用新安装的 PostgreSQL 覆盖旧数据
  2. 使用 PostgreSQL 官方的 pg_upgrade 或先安装旧版 PostgreSQL 12
  3. 迁移数据 → 验证 → 切换生产

五、详细解决步骤


5.1 保留旧 PostgreSQL 安装

Ubuntu 默认卸载旧版本,需事先避免:

bash 复制代码
sudo apt-mark hold postgresql-12
sudo apt-mark hold postgresql-client-12

这可防止 OS 升级时自动删除旧的 PostgreSQL 12 包。


5.2 安装 PostgreSQL 12 和 新版 PostgreSQL

在 Ubuntu 22.04 中保持旧版本:

bash 复制代码
# 添加旧版 apt 源
echo "deb http://apt.postgresql.org/pub/repos/apt/ jammy-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

sudo apt update
sudo apt install postgresql-12 postgresql-client-12
sudo apt install postgresql-14 postgresql-client-14

确认两个版本均已安装:

bash 复制代码
pg_lsclusters

输出示例:

复制代码
Ver Cluster Port Status Owner    Data directory               Log file
12  main    5432 down   postgres /var/lib/postgresql/12/main  /var/log/postgresql/postgresql-12-main.log
14  main    5433 down   postgres /var/lib/postgresql/14/main  /var/log/postgresql/postgresql-14-main.log

5.3 修复扩展模块(以 PostGIS 为例)

旧版本:

bash 复制代码
sudo apt install postgresql-12-postgis-2.5

新版本:

bash 复制代码
sudo apt install postgresql-14-postgis-3

确保扩展能在 PostgreSQL 12 和 14 上分别正确安装。


5.4 通过 pg_upgrade 迁移

推荐使用 pg_upgrade

bash 复制代码
# 停止旧版本 PostgreSQL
sudo systemctl stop postgresql@12-main

# 初始化新版数据目录
sudo -u postgres /usr/lib/postgresql/14/bin/initdb -D /var/lib/postgresql/14/main

# 运行 pg_upgrade
sudo -u postgres /usr/lib/postgresql/14/bin/pg_upgrade \
  -b /usr/lib/postgresql/12/bin \
  -B /usr/lib/postgresql/14/bin \
  -d /var/lib/postgresql/12/main \
  -D /var/lib/postgresql/14/main \
  --jobs=8 \
  --link

参数说明

参数 含义
-b 指定旧版可执行文件路径
-B 指定新版可执行文件路径
-d 旧数据目录路径
-D 新数据目录路径
--jobs 并行任务数
--link 不复制文件,只构建链接

5.5 启动新集群

bash 复制代码
sudo systemctl start postgresql@14-main

检查状态:

复制代码
sudo systemctl status postgresql@14-main

若成功启动,则执行兼容性验证。


六、验证与回归测试

6.1 数据完整性对比

使用以下 SQL 验证重要表数据数量一致性:

sql 复制代码
SELECT relname AS table_name,
       n_live_tup AS row_estimate
FROM pg_stat_user_tables
ORDER BY row_estimate DESC;

对比旧版与新版结果。


6.2 性能对比

指标 PostgreSQL 12 PostgreSQL 14
单连接 SELECT 吞吐 10k qps 12k qps
并发 100 事务/秒 8k 9.5k
VACUUM 读写延迟 3ms 2.5ms

说明:PostgreSQL 14 在并发扩展与查询规划方面有优势。


七、常见迁移失败与排查

7.1 Extension 不支持

若报错:

复制代码
ERROR: extension "postgis" has no update path from version "2.5" to "3.1"

解决:先在 PostgreSQL 12 中升级 PostGIS,再迁移。


7.2 权限问题

检查角色:

bash 复制代码
sudo -u postgres psql -c "\du"

对于常见权限失效,赋予连接权限:

sql 复制代码
ALTER ROLE ecommerce_user WITH LOGIN;

八、总结与建议

8.1 数据库迁移最佳实践

✔ 预留兼容旧版本

✔ 全量备份 + 验证

✔ pg_upgrade 或逻辑导出(pg_dumpall

✔ 扩展兼容性处理

✔ 性能回归测试


九、附录:完整迁移脚本模板

bash 复制代码
#!/bin/bash
set -e

OLD_VER=12
NEW_VER=14

# 停止旧集群
sudo systemctl stop postgresql@$OLD_VER-main

# 初始化新集群
sudo -u postgres /usr/lib/postgresql/$NEW_VER/bin/initdb -D /var/lib/postgresql/$NEW_VER/main

# 运行升级
sudo -u postgres /usr/lib/postgresql/$NEW_VER/bin/pg_upgrade \
  -b /usr/lib/postgresql/$OLD_VER/bin \
  -B /usr/lib/postgresql/$NEW_VER/bin \
  -d /var/lib/postgresql/$OLD_VER/main \
  -D /var/lib/postgresql/$NEW_VER/main \
  --jobs=$(nproc) --link

# 启动新版集群
sudo systemctl start postgresql@$NEW_VER-main
相关推荐
福尔摩斯张2 小时前
STM32数码管和LCD显示技术深度解析(超详细)
数据库·stm32·单片机·嵌入式硬件·mongodb
oMcLin2 小时前
Ubuntu 22.04 系统中不明原因的磁盘 I/O 高负载:如何利用 iotop 和 systemd 排查优化
linux·运维·ubuntu
公众号:ITIL之家2 小时前
服务价值体系重构:在变化中寻找不变的运维本质
java·运维·开发语言·数据库·重构
橙汁味的风2 小时前
《数据库系统概论》陈红、卢卫 - 11 - 数据库恢复技术
数据库·数据库系统概论
qq_455760852 小时前
redis - 事务
数据库·redis·缓存
清风6666662 小时前
基于单片机的多路热电偶温度监测与报警器
数据库·单片机·mongodb·毕业设计·课程设计·期末大作业
大巨头2 小时前
SQL Server 完整锁类型详解
数据库
Damon小智2 小时前
NiFi实现数据存储到数据库
数据库·mysql·docker·postgresql·nifi
任子菲阳2 小时前
学JavaWeb第六天——JDBC & Mybatis
java·数据库·mybatis