最近把测试环境升级到了PostgreSQL 14的开发版本,想提前体验一下新特性。结果踩了不少坑,有几个问题让我熬了好几个夜才解决。本文记录了这些踩坑的经历,包括连接数暴增、查询性能退化、复制延迟、扩展兼容性、参数变化等问题,以及每个问题的排查过程和解决方案。如果你也在考虑升级PostgreSQL 14,希望这篇文章能帮你提前避坑。
一、背景介绍
先说说为什么要升级PostgreSQL 14。
我们的生产环境用的是PostgreSQL 12,已经跑了一年多了,整体比较稳定。但是PostgreSQL 13发布之后,有几个新特性我们很感兴趣,比如并行真空、增量排序等。后来听说PostgreSQL 14的开发版本已经可用了,而且有更多令人期待的特性,比如多范围类型、存储过程改进、性能提升等。
于是我决定先在测试环境升级到PostgreSQL 14的开发版本,试试水。本来以为升级过程会很顺利,毕竟PostgreSQL的大版本升级一直都比较平滑。结果没想到,踩了好几个坑,有几个问题还挺严重的,熬了好几个夜才解决。
本文就把这些踩坑的经历记录下来,每个问题都包括现象、排查过程、根本原因和解决方案。希望能帮到同样在升级PostgreSQL 14的同学。
需要说明的是,我用的是开发版本,有些问题可能在正式版中已经修复了。但是升级过程中的排查思路和方法论,应该还是有参考价值的。
二、坑一:升级后连接数暴增
第一个坑是升级之后连接数暴增。
现象
升级之后第二天,监控告警说数据库连接数接近上限了。我们的max_connections设置的是200,平时正常使用大概在50到80之间。升级之后突然涨到了180多,差点把数据库打挂。
排查过程
首先我查了一下pgstatactivity,看看都是哪些连接。发现大部分连接都是来自应用服务器的,而且很多连接的状态是idle,也就是空闲连接。
然后我查了应用服务器的连接池配置,发现连接池的最大连接数设置的是每个实例20个,我们有10个应用实例,总共200个。这个配置在PostgreSQL 12的时候是没问题的,因为连接池会复用连接,不会真的创建200个连接。
但是升级到14之后,为什么连接数突然涨上去了呢?
我仔细对比了一下,发现升级之后应用的响应时间变慢了。响应时间变慢意味着每个连接的持有时间变长了,连接池里的连接来不及释放,所以需要创建更多的连接。
那为什么响应时间变慢了呢?我查了慢查询日志,发现有几个查询的执行时间比以前长了很多。
根本原因
经过仔细排查,发现是因为PostgreSQL 14改变了某些查询的执行计划。具体来说,是因为优化器的估算发生了变化,导致几个复杂查询选择了更差的执行计划。
其中一个查询是一个多表关联的报表查询,在PG12中用的是Hash Join,在PG14中变成了Nested Loop,性能差了几十倍。
解决方案
临时解决方案是给这几个查询加了Hint,强制使用Hash Join。然后收集了相关表的统计信息,更新之后优化器重新选择了正确的执行计划。
长期来看,需要在升级之后对所有重要查询做性能测试,确保执行计划没有退化。
三、坑二:VACUUM变慢导致表膨胀
第二个坑是VACUUM变慢导致表膨胀。
现象
升级之后一周左右,发现有几张大表的占用空间快速增长。其中一张表本来是50GB,一周之内涨到了80GB。而且查询性能也在下降,因为表变大了,扫描的数据量更多了。
排查过程
首先查了一下这几张表的统计信息,发现死元组的比例很高,说明VACUUM没有及时清理死元组。
然后查了VACUUM的执行情况,发现自动真空的执行频率比以前低了,而且每次执行的时间变长了。
我手动执行了一次VACUUM,发现确实比PG12慢了很多。一张50GB的表,在PG12中大概需要20分钟,在PG14中需要一个多小时。
根本原因
查了Release Notes和邮件列表,发现PostgreSQL 14对VACUUM做了一些改动,包括并行真空的改进。但是在某些情况下,新的VACUUM策略反而会变慢,尤其是对于有很多死元组的大表。
具体来说,是因为PG14在VACUUM的时候会做更多的索引清理工作,而且并行度的计算方式发生了变化,导致在某些配置下并行度不够。
解决方案
临时解决方案是手动调整了vacuumcostlimit和vacuumcostdelay参数,让VACUUM跑得更快一些。同时增加了maintenanceworkmem,让VACUUM可以一次处理更多的数据。
另外,对于特别大的表,改用了pg_repack或者VACUUM FULL来回收空间,比普通的VACUUM更高效。
长期来看,需要监控VACUUM的执行情况,及时调整参数。
四、坑三:流复制延迟增大
第三个坑是流复制延迟增大。
现象
我们有一主一从的流复制架构,升级之后发现从库的延迟明显增大了。以前延迟一般在几毫秒到几十毫秒,升级之后经常出现几秒甚至几十秒的延迟。
排查过程
首先查了从库的接收和回放进程,发现接收是正常的,但是回放速度跟不上。也就是说,WAL日志已经传到从库了,但是从库回放得慢。
然后查了从库的系统资源,发现CPU和IO都不算高,但是回放就是慢。
我对比了一下WAL的生成速度,发现主库的WAL生成速度比以前快了一些。可能是因为PG14的某些操作产生了更多的WAL。
根本原因
经过排查,发现是因为PG14对WAL的格式做了一些调整,从库回放的时候需要做更多的处理。而且我们的从库配置比较低,CPU性能不够,导致回放速度跟不上。
另外,我们用了同步复制,主库需要等从库确认之后才能提交,从库延迟增大之后,主库的写入性能也受到了影响。
解决方案
临时解决方案是把同步复制改成了异步复制,先保证主库的写入性能。然后给从库升级了配置,增加了CPU和内存。
另外,调整了从库的walbuffers和maxwal_size参数,让从库可以更好地处理WAL。
长期来看,需要监控复制延迟,确保从库的配置跟得上主库。
五、坑四:扩展不兼容
第四个坑是扩展不兼容。
现象
升级之后,有几个扩展用不了了。其中最严重的是pgstatstatements,这个扩展是我们用来监控慢查询的,非常重要。升级之后,pgstatstatements的视图查不到数据了。
另外还有几个扩展,比如pgbuffercache、pgfreespacemap,也都出现了不同程度的问题。
排查过程
首先查了一下扩展的版本,发现这些扩展都是针对PG12编译的,和PG14不兼容。
然后我尝试重新编译这些扩展,发现有些扩展的API发生了变化,编译报错。比如pgstatstatements在PG14中增加了一些新的字段,需要修改代码才能编译通过。
根本原因
PostgreSQL的大版本升级经常会改变扩展的API,尤其是开发版本,API变化更大。很多第三方扩展还没有来得及适配PG14,所以会出现不兼容的问题。
解决方案
对于官方自带的扩展(比如pgstatstatements),用PG14自带的版本重新安装就好了。我们之前用的是旧版本的扩展,升级数据库的时候没有同步升级扩展。
对于第三方扩展,需要等作者适配PG14,或者自己修改代码适配。在适配完成之前,只能先不用这些扩展,或者留在旧版本的PostgreSQL上。
建议在升级之前,先确认所有用到的扩展都有支持新版本的版本。
六、坑五:参数变化导致行为改变
第五个坑是参数变化导致行为改变。
现象
升级之后,有一些应用的行为发生了微妙的变化,但是又说不上来哪里不对。比如有些查询的结果排序和以前不一样了,有些事务的隔离级别表现不同了。
排查过程
我仔细对比了PG12和PG14的参数,发现有几个参数的默认值发生了变化。
其中一个是idleintransactionsessiontimeout,在PG12中默认是0(不超时),在PG14中默认变成了1小时。我们有一些长事务,升级之后被自动终止了,导致应用报错。
另一个是password_encryption,默认从md5变成了scram-sha-256。我们有一些老的客户端不支持scram认证,升级之后连不上数据库了。
还有一些优化器相关的参数默认值也变了,导致执行计划的选择发生了变化。
根本原因
每个PostgreSQL大版本都会调整一些参数的默认值,这是正常的。但是如果没有注意到这些变化,就可能导致应用行为改变。
解决方案
升级之后,仔细检查所有参数的默认值变化,对于影响应用行为的参数,改回原来的值,或者调整应用来适应新的默认值。
我们的做法是,把所有重要参数都显式设置在postgresql.conf中,不依赖默认值。这样升级的时候就不会因为默认值变化而出问题了。
七、坑六:逻辑复制问题
第六个坑是逻辑复制的问题。
现象
我们有一个逻辑复制的订阅,从主库复制几张表到另一个库做数据分析。升级之后,逻辑复制断了,而且重新初始化也失败。
排查过程
查了日志,发现逻辑复制的进程报错,说WAL格式不兼容。因为PG14的逻辑复制协议发生了一些变化,旧版本的订阅者无法解析新版本的WAL。
根本原因
PostgreSQL的逻辑复制协议在大版本之间可能不兼容。如果发布者和订阅者的版本不一致,就可能出现问题。
解决方案
把订阅者也升级到了PG14,逻辑复制就恢复正常了。
建议在使用逻辑复制的时候,发布者和订阅者尽量保持大版本一致,或者确认两个版本之间的逻辑复制是兼容的。
八、升级建议
踩了这么多坑,总结一些升级建议。
1. 不要在生产环境直接升级开发版本
开发版本不稳定,可能有各种bug。如果想体验新版本,先在测试环境充分测试,等正式版发布之后再升级生产环境。
2. 升级前做好备份
升级之前一定要做全量备份,最好是文件系统级别的备份。这样升级出问题的时候可以快速回滚。
3. 充分测试
升级之后要做充分的测试,包括功能测试、性能测试、压力测试。重点测试常用的查询和事务,确保执行计划没有退化,性能没有下降。
4. 检查扩展兼容性
确认所有用到的扩展都有支持新版本的版本。对于不兼容的扩展,提前找到替代方案或者自己适配。
5. 检查参数变化
仔细阅读新版本的Release Notes,了解参数默认值的变化和行为的改变。对于重要的参数,显式设置,不依赖默认值。
6. 监控升级后的表现
升级之后密切监控数据库的各项指标,包括连接数、查询性能、复制延迟、表大小等。发现异常及时处理,不要等问题积累大了再解决。
7. 有回滚方案
升级之前制定好回滚方案,如果升级出问题,能快速回滚到旧版本。减少故障时间。
九、写在最后
PostgreSQL 14有很多令人期待的新特性,升级是值得的。但是大版本升级从来都不是一件简单的事情,需要充分的准备和测试。
我这次踩的这些坑,有一些是开发版本的bug,有一些是我自己准备不足导致的。希望通过这篇文章,能让大家在升级的时候少走一些弯路。
如果你也在升级PostgreSQL,或者准备升级,有什么问题或者经验,欢迎在评论区交流。
最后用一句话结束本文:"升级有风险,操作需谨慎。"做好充分的准备,才能平稳地完成升级,享受新版本带来的好处。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录