我们把生产数据库从PostgreSQL 12迁移到了15,过程中踩了不少坑。
本文分享完整的迁移实战,包括迁移前准备、迁移方案、迁移步骤、验证方法、回滚方案,以及踩过的坑和经验总结。
一、为什么要迁移
1. 旧版本的问题
我们的生产数据库用的是PostgreSQL 12,已经用了三年。
遇到的问题:
- 12版本即将停止维护
- 一些新特性用不了(如MERGE、更好的分区表)
- 性能不如新版本
- 一些bug在新版本中修复了
- 社区支持逐渐减少
2. 新版本的吸引力
PostgreSQL 15有很多吸引我们的特性:
- MERGE语句
- 更强大的逻辑复制
- 性能提升
- 更好的分区表
- 更完善的监控
- 安全增强
3. 迁移的目标
我们的迁移目标:
- 从PostgreSQL 12升级到15
- 停机时间尽量短
- 数据不丢失
- 性能不下降
- 可以回滚
二、迁移前准备
迁移前的准备非常重要,准备越充分,迁移越顺利。
1. 环境准备
首先准备新环境。
- 新服务器:配置和旧服务器相当或更好
- 安装PostgreSQL 15
- 配置参数(sharedbuffers、workmem等)
- 安装必要的扩展(如pgstatstatements)
- 网络配置,确保新旧服务器互通
2. 数据库评估
对旧数据库做全面评估。
- 数据量:多大?
- 表数量:多少张表?
- 大表:哪些表特别大?
- 索引:有多少索引?
- 扩展:用了哪些扩展?
- 存储过程:有多少函数和存储过程?
- 定时任务:有哪些定时任务?
-- 查看数据库大小
SELECT pg_size_pretty(pg_database_size('mydb'));
-- 查看表大小
SELECT
relname,
pg_size_pretty(pg_total_relation_size(relid)) as size
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 20;
-- 查看扩展
SELECT * FROM pg_extension;3. 兼容性检查
检查应用和数据库的兼容性。
- 应用用的驱动是否支持PG 15
- ORM是否支持
- SQL语句是否有不兼容的语法
- 扩展是否有PG 15版本
- 函数和存储过程是否兼容
常见的不兼容:
- 一些废弃的函数
- 配置参数变化
- 系统视图变化
- 扩展不兼容
4. 测试环境验证
在测试环境先做一次完整迁移。
- 用生产数据的副本测试
- 跑应用的测试用例
- 性能测试
- 验证所有功能
- 记录问题和解决方案
测试环境验证通过后,再考虑生产迁移。
5. 备份
迁移前一定要备份。
# 逻辑备份
pg_dump -U postgres -Fc mydb > mydb.dump
# 物理备份(如果用PITR)
pg_basebackup -U postgres -D /backup备份要验证可恢复,不要只备份不验证。
三、迁移方案选择
PostgreSQL迁移有几种方案,各有优缺点。
1. 方案一:pg_dump逻辑备份恢复
最简单的方案。
步骤:
- 旧库pg_dump导出
- 新库pg_restore导入
- 验证数据
- 切换应用
优点:
- 简单,容易操作
- 可以跨大版本
- 可以重建索引,优化存储
缺点:
- 停机时间长(数据量大时)
- 导出导入期间不能写
适合:数据量不大(100GB以下),可以接受较长停机时间。
2. 方案二:pg_upgrade原地升级
用pg_upgrade工具升级。
步骤:
- 安装新版本
- 停止旧库
- 运行pg_upgrade
- 启动新库
- 验证
优点:
- 速度快,不需要导出导入
- 停机时间较短
缺点:
- 需要在同一台机器
- 不能跨操作系统
- 出问题回滚困难
- 对环境要求高
适合:同机升级,数据量大,希望停机时间短。
3. 方案三:逻辑复制
用逻辑复制做零停机迁移。
步骤:
- 新库创建订阅
- 旧库创建发布
- 数据同步
- 等追平后,切换应用
- 停止旧库
优点:
- 停机时间极短(秒级)
- 可以跨版本、跨机器
- 可以先验证再切换
缺点:
- 配置复杂
- 需要旧库支持逻辑复制(PG 10+)
- 大对象不支持
- DDL同步有限制
适合:数据量大,要求停机时间短,有技术能力。
4. 我们的选择
我们的数据量约500GB,要求停机时间尽量短。
最终选择了逻辑复制方案:
- 先搭建逻辑复制,同步数据
- 等追平后,在低峰期切换
- 停机时间只有几分钟
四、迁移步骤(逻辑复制方案)
下面是我们的详细迁移步骤。
1. 第一步:配置旧库(发布端)
在旧库(PG 12)上配置发布。
-- 修改配置,开启逻辑复制
-- postgresql.conf
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
-- 重启数据库
-- 创建发布
CREATE PUBLICATION migration_pub FOR ALL TABLES;
-- 创建复制用户
CREATE ROLE replication_user WITH REPLICATION LOGIN PASSWORD 'password';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replication_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO replication_user;注意:
- wal_level要改成logical,需要重启
- 复制用户要有足够的权限
- FOR ALL TABLES会包含所有表,也可以指定表
2. 第二步:配置新库(订阅端)
在新库(PG 15)上配置订阅。
-- 先创建表结构(用pg_dump --schema-only)
-- 在旧库执行
pg_dump -U postgres --schema-only -Fc mydb > schema.dump
-- 在新库执行
pg_restore -U postgres -d mydb schema.dump
-- 创建订阅
CREATE SUBSCRIPTION migration_sub
CONNECTION 'host=old-host port=5432 dbname=mydb user=replication_user password=password'
PUBLICATION migration_pub
WITH (copy_data = true);注意:
- 要先创建表结构,再创建订阅
- copy_data = true表示先全量同步,再增量同步
- 表结构要一致,否则同步会出错
3. 第三步:监控同步进度
创建订阅后,监控同步进度。
-- 在新库查看订阅状态
SELECT * FROM pg_stat_subscription;
-- 查看复制延迟
SELECT
pid,
client_addr,
state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
pg_wal_lsn_diff(sent_lsn, replay_lsn) as delay_bytes
FROM pg_stat_replication;等延迟为0,表示数据追平了。
4. 第四步:同步序列
逻辑复制不会自动同步序列,需要手动同步。
-- 在旧库查看序列当前值
SELECT sequence_name, last_value FROM sequences;
-- 在新库设置序列
SELECT setval('seq_name', 10000);可以写个脚本,批量同步所有序列。
5. 第五步:切换前准备
切换前,做好准备。
- 通知相关人员
- 选择低峰期(如凌晨)
- 准备回滚方案
- 确认数据同步完成
- 确认序列同步完成
- 确认无未完成的事务
6. 第六步:切换
切换的步骤:
- 停止应用(或切到维护模式)
- 等旧库没有新的写入
- 确认新库数据追平
- 修改应用配置,指向新库
- 启动应用
- 验证功能
整个切换过程,我们用了约5分钟。
7. 第七步:切换后验证
切换后,全面验证。
- 数据一致性:对比新旧库的数据
- 功能测试:核心功能是否正常
- 性能测试:响应时间是否正常
- 监控:CPU、内存、连接数
- 错误日志:有没有报错
验证通过后,迁移完成。
五、踩过的坑
迁移过程中,我们踩了不少坑。
1. 坑一:大对象不支持逻辑复制
问题: 我们的数据库有大对象(blob),逻辑复制不支持,同步后大对象丢失了。
解决方案:
- 用pg_dump单独导出大对象
- 在新库导入
- 或者把大对象改成bytea类型
经验: 迁移前检查有没有大对象,逻辑复制不支持。
2. 坑二:序列不同步
问题: 切换后,插入数据时报主键冲突。
原因: 逻辑复制不同步序列,新库的序列还是初始值。
解决方案:
- 切换前同步所有序列
- 写脚本批量同步
- 切换后验证序列值
经验: 序列是逻辑复制的常见坑,一定要记得同步。
3. 坑三:扩展不兼容
问题: 旧库用了pgstatstatements扩展,新库安装后版本不兼容。
解决方案:
- 在新库安装兼容版本的扩展
- 升级扩展:ALTER EXTENSION pgstatstatements UPDATE
- 或者删除后重新创建
经验: 迁移前检查所有扩展,确保新库有兼容版本。
4. 坑四:配置参数变化
问题: 新库用了旧的配置文件,启动报错。
原因: PG 15有一些配置参数废弃或改名了。
解决方案:
- 用PG 15的默认配置文件
- 把自定义的参数迁移过去
- 废弃的参数去掉或改名
经验: 不要直接复制旧配置文件,要用新的默认配置,再修改。
5. 坑五:应用驱动不兼容
问题: 切换后,应用报错,连接不上数据库。
原因: 旧的JDBC驱动不支持PG 15的某些特性。
解决方案:
- 升级应用的数据库驱动
- 迁移前在测试环境验证
- 确保所有应用都升级了驱动
经验: 迁移前要检查所有应用的驱动版本,提前升级。
6. 坑六:性能下降
问题: 切换后,新库性能比旧库差。
原因:
- 新库没有统计信息,查询计划不好
- 索引需要重建
- 配置参数需要调优
解决方案:
- 切换后运行ANALYZE,更新统计信息
- 重建索引(REINDEX)
- 根据实际情况调优参数
- 监控慢查询,逐步优化
经验: 迁移后性能可能暂时下降,要跑ANALYZE和重建索引。
六、回滚方案
迁移要有回滚方案,万一出问题可以回退。
1. 回滚条件
什么情况下回滚:
- 数据不一致,无法修复
- 核心功能不可用
- 性能严重下降,影响业务
- 出现无法解决的bug
2. 回滚步骤
如果需要回滚:
- 停止应用
- 把应用配置改回旧库
- 启动应用
- 新库的增量数据,同步回旧库(如果有)
- 排查问题,准备下次迁移
3. 回滚的时间窗口
- 切换后24小时内,可以回滚
- 超过24小时,新库有了新数据,回滚复杂
- 所以切换后24小时内要密切监控
七、迁移后的优化
迁移完成后,还要做一些优化。
1. 更新统计信息
ANALYZE VERBOSE;2. 重建索引
REINDEX DATABASE mydb;或者对大表单独重建。
3. 参数调优
根据新库的实际情况,调优参数:
- shared_buffers
- work_mem
- maintenanceworkmem
- effectivecachesize
- checkpoint相关参数
4. 监控
迁移后加强监控:
- 慢查询
- 连接数
- CPU、内存、磁盘
- 复制状态(如果还有)
- 设置告警
八、经验总结
这次迁移,我们总结了一些经验。
1. 充分准备
- 迁移前的准备比迁移本身更重要
- 测试环境一定要验证
- 备份一定要可恢复
- 文档要写清楚
2. 选择合适的方案
- 根据数据量和停机要求选方案
- 数据量小用pg_dump
- 数据量大、停机要求高用逻辑复制
- 不要盲目追求零停机,适合的才是最好的
3. 详细的步骤
- 每一步都要写清楚
- 谁执行、执行什么、预期结果
- 回滚方案也要写清楚
- 迁移时按步骤来,不要跳步
4. 充分测试
- 测试环境完整测试
- 应用兼容性测试
- 性能测试
- 回滚测试
5. 低峰期切换
- 选择业务低峰期
- 通知相关人员
- 准备好应急
- 切换后密切监控
九、写在最后
PostgreSQL 15迁移,是一个有风险但有价值的操作。
我们用逻辑复制方案,从12升级到15,停机时间只有5分钟,数据零丢失。虽然踩了一些坑,但最终顺利完成。
迁移的关键是:充分准备、选择合适方案、详细步骤、充分测试、低峰期切换、有回滚方案。
2022年了,PostgreSQL 15已经发布,性能和功能都有提升。如果你的数据库还是旧版本,可以考虑升级。但一定要做好准备,不要盲目操作。
最后,用一句话总结:"数据库迁移,胆大心细。充分准备,按步骤来,有回滚方案,就能顺利完成。"
愿你的数据库迁移,顺利完成,不出问题。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录