elasticSearch内存介绍
在使用elasticSearch过程中或者elasticSearch需要配置升级的时候,elasticSearch内存的分配问题就绕不开了,应该设置多少的堆内存合理?这个问题想必难倒一大批开发者吧,虽然官方给出的建议是堆内存设置机器内存的一半,但毕竟是官方的万金油设置,如果想要更极致的性能应该如何调优呢?本文结合经验和实际浅谈一下这个内存分配的问题
elasticSearch使用的内存种类
elasticSearch使用的内存种类主要分三种:
- 堆内存:即java启动配置的堆大小
- 堆外内存:主要是mmap
- Buffer Cache:系统缓存内存
堆内存在elasticSearch中的作用
堆内存主要用于存储ES进程中的数据结构、文档信息、缓存以及执行搜索操作等。堆内存的大小会直接影响ES的性能,较大的堆内存能够容纳更多的数据和查询,提高搜索性能。然而,过大的堆内存可能导致JVM垃圾回收的开销增大,因此需要在设置时进行权衡。同时Lucene也会使用堆内内存来管理数据结构和索引操作。在es搜索数据的时候,es会从根据搜索把相应索引的分片加载到堆内存里。同时elasticSearch的缓存也是存储在堆内内存里,主要有字段数据缓存、字段数据缓存、字段数据缓存、节点级别的缓存、分布式缓存,这些缓存的作用是应用级别的提速。相当于多次重复条件或者重复的某一个层面的操作会被缓存来提高速度和吞吐量。
堆外内存在elasticSearch中的作用
Elasticsearch的堆外内存主要用于存储直接内存,这是一种在Java应用程序中绕过Java堆而直接与操作系统通信的内存分配方式。堆外内存在ES中的主要作用包括:
- 存储内存映射文件:Elasticsearch使用内存映射文件(mmap)来加速对磁盘上的索引数据的读取。这些内存映射文件通常存储在堆外内存中,而不是Java堆内存中。通过使用内存映射文:ES可以实现高效的数据读取,因为它允许将文件的一部分映射到内存中,而不是将整个文件读入堆内存。
- 网络通信缓冲区:堆外内存也用于存储网络通信的缓冲区。在处理大量网络请求时,使用堆外内存可以减少垃圾回收的开销,提高网络通信的效率。
- 直接内存池:Elasticsearch使用堆外内存池来管理直接内存的分配和释放。这可以帮助降低垃圾回收的频率,因为直接内存不受Java堆内存管理的影响。
- 零拷贝操作:堆外内存支持零拷贝操作,这意味着数据可以直接在堆外内存中进行传输,而不需要在Java堆和堆外内存之间进行额外的拷贝操作。这对于高性能的I/O操作非常重要。
Buffer Cache在elasticSearch中的作用
Buffer Cache 是操作系统级别的缓存,用于存储磁盘上的文件数据块,以减少对物理存储介质的访问。当系统读取文件时,读取的数据块会被缓存到内存中,如果再次访问相同的数据块,系统可以直接从内存中获取,而不需要再次从磁盘读取。这种缓存机制有助于提高文件的读取性能。在elasticSearch中当需要吧索引加载到堆内存的时候就需要使用到系统缓存。
内存分配与调优
在介绍完es中各种内存的作用后,那就涉及如何调优内存相关的了,首先官方推荐的1:1是适合绝大部分场景的万金油配置。但是结合实际的业务还是会有调优的空间。
我们es的机器配置是16g内存,在我们的es机器上执行top命令
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4826 esuser 20 0 21.2g 11.5g 2.6g S 9.0 75.2 48086:32 java
可以看到虚拟内存用了21.2g,实际内存使用了11.5g,而我们的jvm配置是配置8g的堆。
执行free -h
total used free shared buff/cache available
Mem: 15G 9.3G 179M 444K 5.8G 5.7G
Swap: 0B 0B 0B
这台机器就只安装了es,所以根据这些数据我们可以推算出这个实例的内存占用比例:
- 堆内存:8g
- 堆外内存:1.3g(9.3g-8g)
- es使用的buff cache: 2.2g(11.5g-9.3g)
就这个实例来说总体而言可以发现,内存其实是宽裕的没有出现很拥挤的情况,如果是内存比较拥挤,es使用的buff cache会占比很大,因为使用频率的因素,会迅速淘汰其他的系统内存。而实际情况也是如此,堆内存罩住了全量的数据,这使得查询很丝滑。
上面是一个比较良好的环境,那当内存不太够用的时候要怎么优化?
结合业务实际优化内存比例
堆内存就是存一些索引然后存一些缓存,当你的总索引大小很小,但是请求量很大的时候,可以适当增加堆内存的比例,就像我上面的例子,es使用的buff cache(2.2g)占总buff cache(5.8g)的比例很小(这台只部署了es),这时候说明es从磁盘加载索引的压力很小,想要提高吞吐,可以增加堆内存,这样的话缓存和磁盘交换就会更加的少了,可以提高很多qps。
但是如果上面的情况是这样的:es使用的buff cache占总buff cache很大,那说明从磁盘加载索引压力比较大,这时候如果请求的并发量不高,适当的缩减堆内存的大小是可以提高请求的响应速度。但是如果是高并发的话,就得考虑增加机器总内存了。具体可以调整后测试,堆内存是会缓存索引的,buffcache也是会缓存索引的,所以增加哪一个,都不一定会有效果,还是得具体测。当然如果在内存够用的情况下想要提高吞吐,那就优先增加堆内存。堆内存高了吞吐不一定高,但是堆内存小了,吞吐一定上不去。
以上的优化角度是建立在都是简单查询的情况。如果业务是很多复杂查询涉及很多merge操作或者聚合操作的,那堆内存的比例就要高于1/2了。
总结
第一次使用或者暂时没有性能压力的情况,堆内存配置系统内存的一半。
高并发场景要提高堆内存占比
复杂查询场景要提高堆内存占比
题外
堆内存需要缓存索引,堆外内存也要缓存磁盘上的索引。在es上内存是很珍贵的,所以缓存的命中率很重要。比如es里面存了2g的商品数据和100g的日志数据,那商品数据的查询性能就要和100g的日志平均竞争缓存了,在有限的内存下,只要查询几次日志数据,就会极大拉低商品的查询性能,所以es是最需要冷热分离的数据库,查询频率低的数据统统放到冷节点,查询频率高的放热节点。最重要的还是要了解原理,才能知道优化方向