2023-08-08
原文作者:Ressmix 原文地址:https://www.tpvlog.com/article/170

本章,我们来介绍下Elasticsearch的JVM和服务器内存分配。前面的章节,我其实已经讲过,Elasticsearch不建议我们去动JVM相关的默认配置。还有线程池数量的配置,很多人都喜欢去调优线程池,但是在Elasticsearch中,默认的threadpool设置是非常合理的,对于所有的threadpool来说,除了搜索的线程池,都是线程数量设置得跟cpu core一样多。

所以,我们不应该去修改Elasticsearch的这些默认配置。但是,在生产环境部署ES,不可避免要回答一个问题:我的机器上有64G的内存,或者32G的内存,那么一般来说我应该分配多少内存给Elasticsearch的jvm heap呢?

一、JVM堆内存分配

Elasticsearch默认会给jvm heap分配2个G的大小,生产环境肯定不能用这个配置,要重新设置。一般可以通过jvm.options这个配置文件进行设置。

1.1 分配建议

Elasticsearch官方给出的建议是,将机器50%的内存分配给jvm heap,然后留50%的内存给os cache。留给os cache的内存会被Lucene全部用光,用来缓存segment file。

如果我们不需要对任何分词field进行聚合操作,那就不需要使用fielddata,此时可以考虑给os cache更多的内存,因为fielddata是要用jvm heap。如果我们给jvm heap更少的内存,那么实际上es的性能反而会更好,因为更多的内存留给了lucene用os cache提升索引读写性能。

1.2 控制堆内存大小

一般来讲, 给Elasticsearch的heap内存大小最好不要超过32G 。因为只有当heap内存小于32G时,JVM才会用一种compressed oops技术来压缩对象指针(object pointer),解决object pointer耗费过大空间的问题。

object pointer耗费过大空间:object pointer指向heap中的对象,引用的是二进制格式的地址。对于64位的系统来说,当堆内存很大时,64位的object pointer会耗费更多的空间,因为object pointer更大了。同时,过大的object pointer会在CPU,main memory和LLC、L1等多级缓存间移动数据的时候,消耗更多的带宽。

实际上,不用compressed oops时,你如果给jvm heap分配了一个40~50G的内存的可用空间,实际上被object pointer可能都要占据十几G的内存空间,可用的空间量,可能跟使用了compressed oops时的32GB内存的可用空间,20多个G,几乎是一样的。

因此,即使我们有很多内存,但是还是要分配给heap在32GB以内,否则的话浪费更多的内存,降低cpu性能。

综上所述,如果你的Elasticsearch要处理的数据量是十亿级以内的话,建议就是用64G内存的机器比较合适,差不多5台就够了,给jvm heap分配32G,留下32G给os cache。

1.3 超大内存机器

如果我们的机器就是一台超级服务器,内存资源甚至达到了1TB,或者512G,128G,该怎么办?

首先,Elasticsearch官方是建议避免用这种超级服务器来部署ES集群的,但是如果我们只有这种机器可以用的话,我们要考虑以下几点:

  1. 是否需要做大量的全文检索?如果是的话,可以分配32G的内存给ES进程,同时给Lucene留下其余所有的内存,这些剩余内存都会用来缓存segment file,可以提供非常高性能的搜索,几乎所有的数据都是可以在内存中缓存的,ES集群的性能会非常高。
  2. 是否需要做大量的排序或聚合操作?且聚合操作针对数字、日期等不分词字段?如果是的话,那么还是给ES32G的内存即可,其它的留给os cache。
  3. 是否需要针对分词的字段做大量的排序或聚合操作?如果是的话,那么就需要使用fielddata,这就得给jvm heap分配更大的内存了。此时建议运行多个节点在一台机器上。

二、总结

本章,我介绍了Elasticsearch集群部署过程中的JVM堆内存分配的最佳实践。官方建议是JVM堆内存和filesystem os cache各占一半总内存。

阅读全文