PostgreSQL 11升12报错:pg_controldata WAL段大小不匹配求解决
这个问题我之前帮不少用户排查过,核心原因就是新旧PostgreSQL集群的WAL段大小(WAL segment size)不一致——这是pg_upgrade的硬性要求,因为WAL的存储格式和处理逻辑对这个参数高度敏感,必须完全匹配才能顺利升级。
第一步:确认新旧集群的WAL段大小
首先你需要明确两个集群的WAL段大小具体是多少,分别执行以下命令:
检查旧集群(PostgreSQL 11):
/usr/pgsql-11/bin/pg_controldata /var/lib/pgsql/11/data/ | grep "WAL segment size"检查新集群(PostgreSQL 12):
/usr/pgsql-12/bin/pg_controldata /var/lib/pgsql/12/data/ | grep "WAL segment size"
对比两次输出的数值,比如默认是16MB,如果其中一个集群修改过wal_segment_size参数(这个参数只能在initdb时设置,运行时无法修改),就会出现不匹配的情况。
第二步:根据实际情况选择解决方案
方案1:新集群未初始化/可重新初始化(推荐,最快)
如果你的PostgreSQL 12集群刚创建,还没有写入业务数据,直接删除现有数据目录,用和旧集群相同的WAL段大小重新初始化:
先清空新集群的数据目录:
rm -rf /var/lib/pgsql/12/data/*用匹配的WAL段大小执行
initdb,假设旧集群的WAL段大小是64MB,命令如下:/usr/pgsql-12/bin/initdb -D /var/lib/pgsql/12/data/ --wal-segment-size=64注意:
--wal-segment-size的单位是MB,且必须是16的整数倍(PostgreSQL的强制要求)。重新运行
pg_upgrade的预检查命令:/usr/pgsql-12/bin/pg_upgrade --old-datadir /var/lib/pgsql/11/data/ --new-datadir /var/lib/pgsql/12/data/ --old-bindir /usr/pgsql-11/bin/ --new-bindir /usr/pgsql-12/bin/ --check
方案2:新集群已有数据,无法重新初始化
如果新集群已经存储了业务数据,不能重新初始化,那只能通过逻辑备份迁移的方式绕过这个限制:
从旧集群导出全量数据(建议先停止旧集群的写操作,或者添加锁超时参数保证备份一致性):
/usr/pgsql-11/bin/pg_dumpall -U postgres --lock-wait-timeout=60000 > postgres_full_backup.sql确保新集群(PostgreSQL 12)处于运行状态,然后导入备份:
/usr/pgsql-12/bin/psql -U postgres -d postgres -f postgres_full_backup.sql
这种方式虽然比pg_upgrade慢,但能彻底解决WAL段大小不匹配的问题,适合已经有数据的新集群场景。
额外注意事项
pg_controldata命令不需要集群处于运行状态,只要数据目录存在就能查询WAL段大小。- 生产环境使用逻辑备份时,建议在业务低峰期操作,避免影响正常业务。
- 如果旧集群的
wal_segment_size是自定义值,一定要确保新集群初始化时完全匹配,包括单位和数值。
内容的提问来源于stack exchange,提问作者Ram Pratap Maurya

