老年代又占用100%了,顺便发现了vertx-redis-client 的bug
Posted 每天晒白牙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了老年代又占用100%了,顺便发现了vertx-redis-client 的bug相关的知识,希望对你有一定的参考价值。
周五中午陆续收到线上广告检索服务某些节点内存不足的报警,这个服务在我们的广告系统中非常重要,所以需要快速止损,立马重启有问题的节点,可是这个时间点真是尴尬,刚好去食堂吃饭了,还好同事机灵在手机上登录云平台,把有问题的节点重启了
回到工位后,又陆续收到了相同的报警信息,开始和同事一起排查,找到占用内存过高的进程后,通过查看 gc 情况,发现新生代和老年代都满了,内存得不到释放,遇到这种问题就摩拳擦掌,想排查出来,可是毕竟这个服务会影响线上收入,所以我们当时的处理流程如下:
1.先把有问题的节点重启,不影响线上收入
2.留一个问题节点用于排查问题【注意,当问题信息搜集完后,把该问题节点先暂时从集群中摘除】
通过 jmap -histo pid |more 查看内存中占用较大的对象都有什么,发现有个广告创意相关的对象占用挺多,所以需要生成此时的dump文件,查看引用信息
jmap -dump:live,format=b,file=adsearch.dump pid
生成dump文件和下载到本地是个耗时的过程......
下载到本地后,我用了 visualvm 分析 dump 文件
发现有大量Promotion对象【上面说的广告创意对象】,在PrequenceControlService【用于频控的服务】中需要读redis ,因为我们的服务是异步的【用vertx实现】,所以用了配套的 vertx-redis-client, 版本是3.6.3
通过 dump 文件和源代码可知 redis 的 Command 堆积到了 LinkedList 中
在 RedisConnection 这个类中,发现 send 方法不断的往waitling的LinkedList中添加,且添加进去的一直没有得到响应,导致内存暴涨,直至gc
这个版本客户端的设计是有 bug 的,如果连接建立,但 redis server 没有及时响应,请求会一直往队列中添加,但是3.6.3版本的 vertx-redis-client 并没有对添加操作做容量限制,导致内存占用太多
正确的应该有容量限制的,如果超过了最大值,就报错,这样可以保证内存不被撑爆【画外音:但还是解决不了连接不返回的问题】
去github上看 vertx-redis-client 的最新版,发现已经优化了,去掉了RedisConnection,取而代之的是 RedisClient
可以看到在最新版的客户端中,往队列中添加命令时做了容量的限制与判断,默认大小是2048
所以我们的服务升级相应的 jar 包就好了,但是并不能根本解决问题,如果连接再出问题,还是得不到响应,服务还是不可用
至于 redis server 端发生的细节,我还不太清楚,我同事在跟进,大概是因为 client 到 redis server 之间有一层代理,clent与代理之间的链接建立成功后,在 server 端 dba切换节点了,导致连接出了问题,报警时间点和dba切库时间点完全吻合,我们已经和 dba 反映了情况,他们不切节点,就不会发生问题,具体细节还待下周我同事和dba同学一起排查
通过这次线上问题的排查,总结如下:
1.先把有问题的节点重启,不影响线上收入
2.留一台,用于排查问题【注意,问题要用的信息搜集完后,把该节点从集群中摘除】
3.用 linux 常用命令和工具进行进行排查
4.时刻关注项目中用到的开源组件的issue和版本更新,以便了解老版本中的一些bug
对排查jvm相关问题感兴趣的朋友可以查看我之前的文章
以上是关于老年代又占用100%了,顺便发现了vertx-redis-client 的bug的主要内容,如果未能解决你的问题,请参考以下文章