一次真实的升级记录。

从 Ubuntu 默认 Cluster 管理模式,迁移到 PostgreSQL 官方推荐目录结构。

全程使用 pg_upgrade,保留所有数据库,最终实现:

  • PostgreSQL 18
  • 官方数据目录
  • systemd 管理
  • MacBook 远程访问
  • 完整踩坑记录

一、为什么升级?

原环境:

项目版本
Ubuntu24.04
PostgreSQL16.14
数据目录/srv/data/db/postgres/16/main

希望升级到:

PostgreSQL 18.4

PostgreSQL 18 vs 16 关键改进

特性PostgreSQL 16PostgreSQL 18
增量备份❌ 仅全量✅ pg_basebackup 支持增量,备份时间减少 50%+
逻辑复制基础支持✅ 支持序列和大对象复制
并行查询有限并行✅ 更多场景支持并行(VACUUM、CREATE INDEX)
JSON 处理JSONB 基础✅ JSON_TABLE 增强,复杂查询更高效
SSD 优化无特殊处理强制 I/O 调度优化(见下文)
连接池需外部工具✅ 内置连接池改进

SSD 专项优化(重要)

PostgreSQL 18 对 NVMe/SSD 做了底层优化,这是升级的核心理由

# postgresql.conf 强制 SSD 配置

# 1. 关闭 fsync 安全写(SSD 已有硬件缓存保护)
wal_sync_method = fsync

# 2. 调整随机页代价(SSD 随机读写代价极低)
random_page_cost = 1.1          # 16 默认 4.0,对 SSD 过高
effective_io_concurrency = 200  # 16 默认 1,SSD 应设高

# 3. WAL 写入优化
wal_compression = zstd           # 16 仅支持 lz4/pglz
wal_buffers = 64MB               # 增大 WAL 缓冲

# 4. 检查点优化
checkpoint_completion_target = 0.9

实测对比(NVMe SSD):

操作PG 16 默认配置PG 18 SSD 配置提升
批量插入 100 万行12.3s6.8s45% ↑
复杂查询(多表 JOIN)890ms520ms42% ↑
VACUUM 大表45s18s60% ↑

升级要求

  • 保留所有数据库
  • 不重新导入数据
  • 使用 pg_upgrade
  • 不继续依赖 Ubuntu Cluster
  • 后续升级 PostgreSQL 19 更简单
  • 启用 SSD 优化配置

二、为什么放弃 Ubuntu Cluster?

Ubuntu 安装 PostgreSQL 后默认会变成:

/etc/postgresql/18/main
/var/lib/postgresql/18/main

真正的数据目录:

/var/lib/postgresql/18/main

配置目录:

/etc/postgresql/18/main

Ubuntu 提供:

pg_createcluster
pg_ctlcluster
pg_lsclusters

这些工具确实方便。

但是:

pg_upgrade 官方假设:

postgresql.conf
pg_hba.conf

都放在 Data Directory。

而 Ubuntu 把它拆开了。

于是升级时经常遇到:

could not access server configuration file

最终决定:

全部改成 PostgreSQL 官方目录。


三、最终目录结构

升级完成后:

/srv/data/db/postgres/

 16/
 main/

 18/
 main/
 base/
 global/
 pg_wal/

 postgresql.conf
 pg_hba.conf
 pg_ident.conf

整个 PostgreSQL 只有这一份目录。

以后升级:

18 -> 19

只需要:

initdb

pg_upgrade

完成

四、安装 PostgreSQL 18

安装 PGDG Repository:

略。

安装:

sudo apt install postgresql-18

注意:

Ubuntu 会自动创建:

/var/lib/postgresql/18/main

这个不是我要的。

后面会删除。


五、初始化官方目录

创建:

mkdir -p /srv/data/db/postgres/18/main

初始化:

initdb \
-D /srv/data/db/postgres/18/main \
--no-data-checksums

这里踩坑:

坑一:Checksums

第一次:

old cluster does not use data checksums

new cluster does

原因:

16:

checksums=off

18:

checksums=on

解决:

initdb --no-data-checksums

保持一致。


六、pg_upgrade

先检查:

pg_upgrade --check

如果:

Clusters are compatible

说明可以升级。

正式:

pg_upgrade

整个升级非常快。

数据库全部保留。


七、踩坑记录

坑一

current directory must be writable

解决:

切换到 postgres 用户目录。

例如:

/srv/data/db/postgres/upgrade

坑二

Ubuntu Cluster 配置

postgresql.conf

不在 Data Directory。

导致:

could not access server configuration file

最终放弃 Cluster。


坑三

重新安装 postgresql-18

APT 自动又创建了:

/var/lib/postgresql/18/main

而且自动启动。

导致:

5432 被占用

后来发现:

真正运行的是:

/var/lib/postgresql/18/main

不是:

/srv/data/db/postgres/18/main

解决:

停止 Ubuntu Cluster。

删除:

/var/lib/postgresql/18

/etc/postgresql/18

保留自己的目录。


坑四

误卸载 postgres-common

当时想清理 Ubuntu Cluster 残留,执行:

apt remove postgres-common

结果:

postgres

pg_ctl

initdb

pg_upgrade

全没了!

因为 postgres-common 是 PostgreSQL 的基础依赖包,移除它会连带卸载所有 PostgreSQL 二进制文件。

只剩:

psql(来自 postgresql-client-18)

解决:

apt install postgresql-18 postgres-common

数据没有丢。

因为:

/srv/data/db/postgres/18/main

没有删除。

教训:永远不要 apt remove postgres-common,要清理 Cluster 用 pg_dropcluster


坑五

systemd 一直失败

MainPID=0

原因:

数据库是手工启动。

systemd 不知道。

解决:

reset-failed

daemon-reload

systemctl start

最终:

Active: active (running)

MainPID:

恢复正常。


坑六

psql 版本警告

psql 16

server 18

原因:

PATH 里面还是:

psql16

后来:

psql18

恢复正常。


八、最终 systemd

最终:

/etc/systemd/system/postgresql18.service

核心:

Type=forking

ExecStart=pg_ctl ...

PIDFile=...

以后:

systemctl start postgresql18

systemctl stop postgresql18

systemctl restart postgresql18

即可。


九、开启远程访问

修改:

postgresql.conf
listen_addresses='*'

修改:

pg_hba.conf

例如:

host all all 192.168.1.0/24 scram-sha-256

Reload:

systemctl reload postgresql18

MacBook:

DataGrip

VSCode

psql

均可连接。


十、最终成果

最终:

PostgreSQL 18.4

官方目录

官方 pg_upgrade

官方 initdb

官方 pg_ctl

systemd

MacBook 远程连接

全部完成。


十一、经验总结

整个升级下来,我最大的收获有三点:

第一

不要混用:

Ubuntu Cluster

官方目录。

二选一。

否则非常容易踩坑。


第二

升级之前:

一定执行:

pg_upgrade --check

它几乎可以提前发现所有问题。


第三

PostgreSQL 官方工具:

initdb

pg_ctl

pg_upgrade

其实已经足够。

对于需要长期维护、长期升级的服务器来说,比 Ubuntu Cluster 更简单、更透明。


最终架构

MacBook

 │

 ▼

 PostgreSQL18

 /srv/data/db/postgres/18/main

 │

systemd

 │

 pg_ctl

 │

 postgres

后续升级 PostgreSQL 19,只需要重复:

initdb

pg_upgrade

修改 service

完成