记一次Cassandra Java堆外内存排查经历

背景

最近准备上线cassandra这个产品,同事在作一些小规格ECS(8G)的压测。压测时候比较容易触发OOM Killer,把cassandra进程干掉。问题是8G这个规格我配置的heap(Xmx)并不高(约6.5g)已经留出了足够的空间给系统。只有多是Java堆外内存使用超出预期,致使RES增长,才可能触发OOM。html

调查过程

0.初步怀疑是哪里有DirectBuffer泄漏,或者JNI库的问题。
1.按惯例经过google perftools追踪堆外内存开销,可是并未发现明显的异常。
2.而后用Java NMT 看了一下,也没有发现什么异常。java

3.查到这里思路彷佛断了,由于跟DirectBuffer彷佛没啥关系。这时候我注意到进程虚拟内存很是高,已经超过ECS内存了。怀疑这里有些问题。node

4.进一步经过/proc/pid/smaps 查看进程内存地址空间分布,发现有大量mmap的文件。这些文件是cassandra的数据文件。oracle

此时这些mmap file 虚拟内存是2G,可是物理内存是0(由于我以前重启过,调低过内存防止进程挂掉影响问题排查)。ide

显然mmap的内存开销是不受JVM heap控制的,也就是堆外内存。若是mmap的文件数据被从磁盘load进物理内存(RES增长),Java NMT和google perftool是没法感知的,这是kernel的调度过程。ui

5.考虑到是在压测时候出现问题的,因此我只要读一下这些文件,观察下RES是否会增长,增长多少,为啥增长,就能推断问题是否是在这里。经过下面的命令简单读一下以前导入的数据。google

cassandra-stress read duration=10m cl=ONE -rate threads=20 -mode native cql3 user=cassandra password=123 -schema keysp
ace=keyspace5 -node core-3

6.能够观察到压测期间(sar -B),major page fault是明显上升的,由于数据被实际从磁盘被load进内存。url

同时观察到mmap file物理内存增长到20MB:spa

最终进程RES涨到7.1g左右,增长了大约600M:线程

若是加大压力(50线程),还会涨,每一个mmap file物理内存会从20MB,涨到40MB

7.Root cause是cassandra识别系统是64仍是32来肯定要不要用mmap,ECS都是64,可是实际上小规格ECS内存并很少。

结论

1.问题诱因是mmap到内存开销没有考虑进去,具体调整方法有不少。能够针对小规格ECS下降heap配置或者关闭mmap特性(disk_access_mode=standard)
2.排查Java堆外内存仍是比较麻烦的,推荐先用NMT查查,用起来比较简单,配置JVM参数便可,能够看到内存申请状况。


原文连接 本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索