[TOC]

场景

因为在集群中,GC频繁:

初步排查

该集群的Heap是分配了 32G,从图中可以看到,每次都达到了 28G。

查看集群数据总量

1
GET /_cat/allocation?v&h=shards,disk.indices,disk.used,disk.avail

查看各节点的segement memorycache占用量

1
GET /_cat/nodes?v&h=id,port,v,m,fdp,mc,mcs,sc,sm,qcm,fm,im,siwm,svmm

Heap Dump 分析

因为通常集群的Dump文件都非常大,本地开发机器无法进行分析。具体如何分析超大的Dump文件,可以参考我之前的文章Linux 中分析超大 JVM dump 文件,这里我就不赘述了。

这里主要说另一个问题:Docker部署的集群,如何导出堆栈信息。

注意:我这里使用的是7.4.0自带jdk的集群版本。

Docker内进行jmap

当我们使用docker exec -it es01 /bin/bash进入到es的镜像内后,直接使用jmap是找不到的命令的。

不过,我们可以在这个图中发现,因为使用的是自带的jdk,所以我们需要使用jdk/bin/jmap这样来使用。

我们先尝试使用jps查看:

1
jdk/bin/jps -lv

可以看到,当前es 的进程PID了(在Docker内,通常都是1)。

再使用jstack,尝试查看当前堆栈:

1
jdk/bin/jstack 1

却得到一个错误:

1
2
# jdk/bin/jstack 1
1: Unable to open socket file /proc/1/root/tmp/.java_pid1: target process 1 doesn't respond within 10500ms or HotSpot VM not loaded

通过搜索响应的解决方案,这是因为镜像内执行用户不同导致的。在这里详细说明了如何解决,可以在exec时,指定用户和用户组,进入后,就可以正常执行了。

1
docker exec -u 1000:0 -it es01 /bin/bash

Eclipse MAT

从这里下载MAT Download,因为集群的Dump文件通常有几十G了,所以在解析时,需要找一台内存大机器以及配置MAT的最大内存设置:

  • 解压缩MAT后,修改MemoryAnalyzer.ini文件,将内存设置为20GB左右:
1
2
3
4
5
6
-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.700.v20180518-1200
-vmargs
-Xmx20240m
  • dump文件拷贝过来,并执行分析:
1
2
nohup ./ParseHeapDump.sh ./es_heap.bin org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components &
echo $! > pid

这里,我使用了nohup,主要是因为大文件的分析比较耗时,无法保证服务端的shell活动时间。

等待执行完毕……

具体分析