从PG的RelCache问题聊起

昨天在回南京的高铁上一个朋友发来一个消息说在华为云上测试rds for pg的时候遇到一个OOM的问题。他们在测试自己的应用的时候,连接池使用后,压测过程中总是出现OOM的问题,发现PG的会话占用的物理内存都在不断地暴增。通过分析发现,和stackoverflow上的一个例子十分相似。

从PG的RelCache问题聊起

他们怀疑是这个PG 8.x版本就已经发现的问题到现在还没有解决。回想一下,这个问题似乎在数年前我也遇到过,好像那时候遇到的是9.x的版本,也是长连接的连接池过一段时间就会出现会话占用大量的物理内存,而且不释放。当时没有仔细分析原因,只是采取了设置idle时间限制,定期重启会话的方式来解决这个问题。

这个问题数年前就在PG官网上被列为一个BUG,BUG号是14234:

从PG的RelCache问题聊起

2016年,阿里的德哥也发过一篇文章(https://billtian.github.io/digoal.blog/2016/07/09/01.html)介绍了这个在案例云上发现过的问题。并说明了在阿里云上发布的RDS FOR PG中修复了这个BUG。实际上要发现这个BUG还真的不是很容易,一般需要满足几个条件。首先是数据库服务器的内存并不十分充裕,对于一些剩余大量内存的数据库服务器,哪怕会话数量较多,占用的relcache比较大,也不容易出现OOM,因此不容易引起别人的关注。其次是会话数要相对较多,如果只是少量会话,问题不容易显现。第三点是应用中访问大量的数据库对象,如果会话访问的对象数量有限,那么RELCACHE占用的总空间也是有限的,系统运行一定时间后,RELCACHE就会稳定下来。第四是会话采用长连接,因为会话关闭时,backend进程退出,这些缓冲就完全释放了。

这个问题其实在2016年就十分著名了,我在很多地方看到过关于RELCACHE的讨论,在国内的各种技术论坛上也有很多相关的文章。

朋友的测试用例完全符合这个条件。按照BUG

首先我们看初试状态的会话,占用的内存是7448,7M多.测试完成后:

通过D-SMART我们也发现这个会话排在物理内存占用的第一位

通过会话详情的分析,可以看到这个PG会话只使用了72M共享内存,私有内存占用了6.8GB。

这个会话占用的内存居然高达6GB+。看样子relcache扩张不受限的问题,在PG 11核心上依然存在。如果存在几十个甚至上百个个这样的会话,再大内存的服务器也撑不住啊。

在测试过程中,我们还遇到了DATA_STACK_SIZE exceed的问题。刚开始执行select MTDB_Initialize(‘tenant’, 100, 1000, true);的时候,会出现报错,后来发现这是PG的一个参数max_locks_per_transaction有关。当我们创建一些新的对象的时候,pg_locks中可以看到一些锁,如下图。


这些锁的目的是确保在一个事务没有完成之前,这些相关对象的数据字典不会被错误的删除或者修改。这些锁并不存储于backend的私有内存中,而是存在在共享内存中,而这些锁的总数是由max_locks_per_transaction和max_connections的乘积决定的。关于这方面的分析,瀚高的类总也翻译过相关的文章,有兴趣的朋友可以阅读相关文章做详细的了解,我这里就不细说了(https://blog.csdn.net/weixin_46199817/article/details/111554760)。

我们看到,随着这条命令的执行,锁的数量在快速的增加,一旦这个数量达到了刚才所说的限额,那么就会出现out of shared memory的报错了。在PG 11里,这个报错就是DATA_STACK_SIZE exceed。

我们在同是PG分支的人大金仓数据库上试一试。

人大金仓是基于PG 9的,因此报错信息有些不一样,直接报出了共享内存不足的问题。我们需要首先调整一下参数。

开始跑测试之后很快D-SMART就收到了内存方面的告警。

可以看出一个会话占用了大部分系统内存。


最终系统内存被全部消耗殆尽,连SWAP也被消耗光了。于是OS的OOM KILLER杀掉了这个会话。

从上面的测试可以看出,在人大金仓中也没有修复PG中的RELCACHE占用过多内存的BUG。

实际上RELCACHE的问题并不是一个十分难解决的问题,主要是遇到这样的问题的应用场景比较不容易遇到,所以在PG在开源的PG中并没有进行修正。实际上对BACKEND中RELCACHE占用内存的总数做一个限制,如果达到了限制就采用LRU算法进行淘汰,这个问题是不难解决的。从德哥的文章里也可以看到阿里云的RDS FOR PG就已经解决了这个问题。但是我今天测试的两个以PG为基础的国产数据库并没有修复这个BUG。开源社区的产品经理(不知道开源软件是否有这样的角色)可能不关注这个问题。国产数据库的产品经理不应该忽视这样一个十分著名的错误。数据库国产化的进程中,我们通过使用开源代码来实现0到1的问题,不过我们不能只是躺在1上面吃开源社区的老本。我们可能无法在短时间内完成1到100的飞跃,但是修复已知的问题,让我们的数据库少一些BUG,应该是国产数据库厂商应该首先做到的。产品经理也应该安排专门的人员收集这些常见的BUG,在自己的产品中加以修复,这样才不会总让人诟病国产化就是100%套壳的问题。




从PG的RelCache问题聊起》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.bookhoes.com/408.html