说明
本文是接上一篇oom记录文章《一次oom我做了什么-(JVM,JMAP,MAT,等,大杂烩)》,后续又发现了一些问题,再追加的一些记录。
回顾
之前出oom问题分析的有些笼统,并且不太准确,之前用mat分析后得出是LogManager这个类相关的问题,确实,这个类是出现oom的原因之一,但不是根本原因,真正的原因是截图中圈出来的Disruptor,不仅在LogManager中出现了,而且在NodeImpl中也出现了。
分析
Disruptor是一个高并发无锁的环形队列,我们采用的是Jraft来做数据同步,而Disruptor正是Jraft中引用的,并且我在Jraft文档中看到,如果是写入吞吐量较高的应用,建议将Disruptor的size调大,Jraft中默认是16384。基于我们的业务场景,想当然的就把16384又扩大了二倍。
那么问题来了,这个size和oom有什么关系?
环形队列的逻辑是队列中数据量到达了设定的阈值后,新进入的将会覆盖原数据,就像一个环一样。
这样的逻辑,队列中的数据量是固定的,最大内存应该也是固定的才对,进来再多数据,只要到了阈值,应该就不会再占用更多内存了,那为何会oom呢?
因为我们设定的业务逻辑,是合并请求,然后一次提交大量数据交给raft来同步,这样是为了减少rpc次数,提高效率,但同时又扩大了每笔提交数据量,所以这个环形队列在我们这个逻辑中就很尴尬了,还没有到16384,可能size还很小但时候,内存已经撑爆了。
于是我们尝试着平衡合并请求的阈值与Disruptor的size,经过大量压测并监控内存使用情况,最终这样平衡,可以解决我们oom的问题。