4年前 (2021-01-01)  jvm |   抢沙发  1341 
文章评分 0 次,平均分 0.0

我们最近花了很多时间跟踪弹性云服务中的各种内存问题。特别是其中一个攻击活动相对较少的小集群,需要进行大量挖掘才能找到答案。

每个节点都有一个固定的内存量,我们为堆保留了大约一半的内存。其余的由JVM和文件缓存使用。通常,JVM使用的内存是恒定的,但是我们看到一些实例,Elasticsearch使用的总内存不断无限制地缓慢增加,直到达到总限制。有时需要几天时间,但它一直在不断攀升。当达到限制时,节点将耗尽内存并重新启动。

所以这是内存泄漏的一个非常明显的迹象。我们使用Yourkit、MAT等工具分析了Elasticsearch,但在堆中找不到任何可以解释这一点的东西,但是Elasticsearch进程的RSS(resident set size)内存在不断增加。我们尝试打开本机内存跟踪,发现内存增加根本不在堆中。

本机内存跟踪(NMT)是JVM中的一个特性,它提供了一种查看JVM内部内存使用情况的方法。它跟踪所有内存分配,并按使用情况对其进行分组。这既提供了内存去向的概述,也提供了分配发生的详细信息。

NMT的报告如下:

排查Elasticsearch本机内存泄漏

然而,即使使用NMT对Elasticsearch过程进行了长时间的分析,操作系统测量的内存使用量的增长速度比NMT报告的要快得多。这表明内存泄漏超出了JVM的跟踪能力。我们有本机内存泄漏

输入跟踪本机内存分配的工具。幸运的是,有人描述了用jemalloc实现这一点的一种方法。

以下是我使用Elasticsearch运行它的步骤:

git clone http://github.com/jemalloc/jemalloc 
cd jemalloc ./autoconf.sh --enable-perf 
make dist 
make 
sudo make install

然后我在启动Elasticsearch之前添加了这些env变量:

export LD_PRELOAD=/usr/local/lib/libjemalloc.so 
export MALLOC_CONF=prof:true,lg_prof_interval:30,lg_prof_sample:17,prof_final:true

我用X-Pack运行了5.1.1版的Elasticsearch,它显示了内存泄漏,我还启用了X-Pack监视功能,只是为了让一些轻量级的索引能够正常运行。然后我运行了一夜,因为我们已经看到这个泄漏在缓慢发生。

随后,生成以下输出:

jeprof --show_bytes --gif /usr/lib/jvm/java-8-oracle/jre/bin/java jeprof*.heap > /tmp/app-profiling.gif

输出如下所示(滚动到底部):

排查Elasticsearch本机内存泄漏

在底部,JVM实际上只引用了80%的内存,因此我们“损失”了20%。这是在运行了24小时之后。当我开始这个过程的时候,这个比例是97%,所以损失一直在增加。

在详细信息中,您可以看到哪个方法分配了内存。最大的罪魁祸首似乎是java.util.zip.Inflaterjava.util.zip.Deflater占“丢失”内存的18.2%。

Inflater和Deflater是使用本机函数实现的,本机函数为缓冲区分配内存。如果您忘记对它们调用end(),则内存永远不会被释放。但是,它实现了一个终结器,如果您忘记了,它应该为您运行end()。但终结器只在完全垃圾回收full gc时调用,并且当所有引用都不存在时。使用较少的集群几乎永远不会完成完整的Full GC,因此在实践中它们从未被清理干净。

我们使用Yourkit查看了InflaterDeflater的使用方法,发现了一些可能忘记关闭它们的地方:

排查Elasticsearch本机内存泄漏

排查Elasticsearch本机内存泄漏

并非所有这些都是真正的泄漏,它们可能仍在使用,但我们对它们进行了调查。这项调查导致了Lucene和Elasticsearch中的各种修复:

http://issues.apache.org/jira/browse/LUCENE-7647

http://github.com/elastic/elasticsearch/pull/22711

为了验证我们是否捕捉到了所有的情况,我们制作了一个小工具来记录我们分配Inflater的时间以及对它调用end()的时间。它是作为一个代理实现的,它对Inflater类进行检测。我们在Elasticsearch 5.1.1上运行了这个工具,它准确地显示了需要修复的地方,而在5.2.1中,它没有显示任何地方(除了一些由于jar缓存而预期的地方)。

我们已经看到,当普通的内存评测工具无法识别内存问题时,它可能在JVM之外。在这种情况下,我们需要窥视它的内部。由于JVM只是一个“普通”的C++程序,所以我们可以使用众所周知的工具和技术来分析它。
排查Elasticsearch本机内存泄漏

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1164.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册