环境介绍
es版本:5.6.4
-Xms31g -Xmx31g
-XX:MaxDirectMemorySize=10g
问题说明
用top命令观察ES使用的物理内存不断增加到54.6G
已知堆内存31G,堆外内存MaxDirectMemorySize 10G,那么内存使用最高应该不超过41G才对。现在内存使用了54.6G明显超过了预估,那么除了已知的41G外,还有哪些我们不知道的地方在占用内存呢?
问题分析
为了弄清楚54.6g内存有哪些部分组成,我打开了内存映射文件 /proc/ES进程号/smaps
首先我们截取文件中的一段来介绍怎么看这个文件:
- 7e1cde88b000-7e1ce4acf000 是该虚拟内存段的开始和结束位置
- r–s内存段的权限,最后一位p代表私有,s代表共享
- 00000000 该虚拟内存段在对应的映射文件中的偏移量
- 08:20 文件的主设备和次设备号
- 21365069 被映射到虚拟内存的文件的索引节点号
- /mnt/ssd1/data/cluster001/SERVICE-ELASTICSEARCH-retro/nodes/0/indices/iB4FRrDrQNSxIp8-VAegbw/3/index/_841x.cfs
被映射到虚拟内存的文件名称。后面带(deleted)的是内存数据,可以被销毁。 - size 是进程使用内存空间,并不一定实际分配了内存(VSS)
- Rss是实际分配的内存(不需要缺页中断就可以使用的)
- Pss是平摊计算后的使用内存(有些内存会和其他进程共享,例如mmap进来的)
- Shared_Clean 和其他进程共享的未改写页面
- Shared_Dirty 和其他进程共享的已改写页面
- Private_Clean 未改写的私有页面页面
- Private_Dirty 已改写的私有页面页面
- Referenced 标记为访问和使用的内存大小
- Anonymous 不来自于文件的内存大小
- Swap 存在于交换分区的数据大小(如果物理内存有限,可能存在一部分在主存一部分在交换分区)
- KernelPageSize 内核页大小
- MMUPageSize MMU页大小,基本和Kernel页大小相同
由介绍可以知道top命令中的RES表示进程实际占有的内存大小,它通过把smaps文件中所有的Rss累计得到的。可以通过以下命令计算:
grep Rss smaps |awk 'BEGIN {sum = 0;} {sum += $2} END{print sum}'
在文件中我找到了31G堆内存的映射:
其中的Rss刚好等于31G。
而剩下内存的大部分被lucene文件占用,我把lucene文件目录部分的过滤出来,统计的Rss和有22G之多。
过滤和统计lucene文件占用RSS的命令如下:
grep -A 5 'SERVICE-ELASTICSEARCH' smaps > lucene_smaps
grep Rss lucene_smaps |awk 'BEGIN {sum = 0;} {sum += $2} END{print sum}'
现在基本可以确定内存超出控制的元凶就是lucene文件的加载。而lucene文件所占用的内存即不属于JVM的堆内存,也不属于MaxDirectMemorySize 控制的堆外内存。因此这块内存是不受ES进程控制的。那么为什么会加载这些Lucene文件呢?
这不得不让我想到了ES的文件存储类型。
5.6.4版本的ES支持simplefs,niofs,mmapfs这3中文件存储类型,配置配置项index.store.type进行配置。可参考:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/index-modules-store.html
我的环境默认使用的是mmapfs。这种存储类型会将lucene索引文件用mmap的方式映射到内存中,这样进程就能够直接从内存中读取lucene数据了。对mmap不了解可以参考:https://www.jianshu.com/p/da998d55ea36
由于使用了内存映射,es进程读取lucene文件的时候读取到的数据就会占用了堆外内存的空间,数据读取完毕后这块内存空间会自动释放。用于我的es环境在压测,因此高并发,不间断的查询使得越来越多的数据被读入堆外内存空间,导致ES进程的总体内存不断上升。
问题解决
虽然es进程占用的内存因为加载lucene文件而升高,但这并不会成为一个问题,因为mmapfs占用的内存是缓存类型的,当其他进程使用到这块内存区域的时候,它将会释放。
如果还是不放心,不希望看到RES指标持续增长的现象,可以将mmapfs模式修改为niofs。这样es就不会使用内存映射的方式了,堆外内存空间也不会上升,RES指标也就稳定了。不过官方还是推荐64位的linux系统使用mmapfs模式。