干货 | 吃透Elasticsearch 堆内存

本文涉及的产品
Elasticsearch Serverless通用抵扣包,测试体验金 200元
简介: 1、什么是堆内存?

image.png

Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。

在 Java 中,堆被划分成两个不同的区域:


新生代 ( Young )、

老年代 ( Old )。

新生代 ( Young ) 又被划分为三个区域


Eden、

From Survivor、

To Survivor。

这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。


2、堆内存的作用是什么?

在虚拟机启动时创建。


堆内存的唯一目的就是创建对象实例,所有的对象实例和数组都要在堆上分配。


堆是由垃圾回收来负责的,因此也叫做“GC堆”,垃圾回收采用分代算法,堆由此分为新生代和老年代。


堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。


但缺点是,由于要在运行时动态分配内存,存取速度较慢。当堆内存因为满了无法扩展时就会抛出java.lang.OutOfMemoryError:Java heap space异常。出现这种情况的解决办法具体参见java调优。


3、堆内存如何配置?

默认情况下,Elasticsearch JVM使用堆内存最小和最大大小为2 GB(5.X版本以上)。


早期版本默认1GB,官网指出:这明显不够。


在转移到生产环境时,配置足够容量的堆大小以确保Elasticsearch功能和性能是必要的。


Elasticsearch将通过Xms(最小堆大小)和Xmx(最大堆大小)设置来分配jvm.options中指定的整个堆。


举例如下:


设置方式一:

在jvm.option配置文件中设置堆内存。


-Xms2g

-Xmx2g

1

2

设置方式二:

通过环境变量设置。

这可以通过注释掉jvm.options文件中的Xms和Xmx设置并通过ES_JAVA_OPTS设置这些值来完成:


ES_JAVA_OPTS="-Xms2g -Xmx2g" ./bin/elasticsearch

ES_JAVA_OPTS="-Xms4000m -Xmx4000m" ./bin/elasticsearch

1

2

4、堆内存的决定因素

堆内存的值取决于服务器上可用的内存大小。


5、堆内存配置建议

将最小堆大小(Xms)和最大堆大小(Xmx)设置为彼此相等。


Elasticsearch可用的堆越多,可用于缓存的内存就越多。但请注意,太多的堆内存可能会使您长时间垃圾收集暂停。


将Xmx设置为不超过物理内存的50%,以确保有足够的物理内存留给内核文件系统缓存。


- 不要将Xmx设置为JVM超过32GB。


大小建议:

宿主机内存大小的一半和31GB,取最小值。

1

2

6、堆内存为什么不能超过物理机内存的一半?

堆对于Elasticsearch绝对重要。

它被许多内存数据结构用来提供快速操作。但还有另外一个非常重要的内存使用者:Lucene。


Lucene旨在利用底层操作系统来缓存内存中的数据结构。 Lucene段(segment)存储在单个文件中。因为段是一成不变的,所以这些文件永远不会改变。这使得它们非常容易缓存,并且底层操作系统将愉快地将热段(hot segments)保留在内存中以便更快地访问。这些段包括倒排索引(用于全文搜索)和文档值(用于聚合)。


Lucene的性能依赖于与操作系统的这种交互。但是如果你把所有可用的内存都给了Elasticsearch的堆,那么Lucene就不会有任何剩余的内存。这会严重影响性能。


标准建议是将可用内存的50%提供给Elasticsearch堆,而将其他50%空闲。它不会被闲置; Lucene会高兴地吞噬掉剩下的东西。


如果您不字符串字段上做聚合操作(例如,您不需要fielddata),则可以考虑进一步降低堆。堆越小,您可以从Elasticsearch(更快的GC)和Lucene(更多内存缓存)中获得更好的性能。


7、堆内存为什么不能超过32GB?

在Java中,所有对象都分配在堆上并由指针引用。普通的对象指针(OOP)指向这些对象,传统上它们是CPU本地字的大小:32位或64位,取决于处理器。


对于32位系统,这意味着最大堆大小为4 GB。对于64位系统,堆大小可能会变得更大,但是64位指针的开销意味着仅仅因为指针较大而存在更多的浪费空间。并且比浪费的空间更糟糕,当在主存储器和各种缓存(LLC,L1等等)之间移动值时,较大的指针消耗更多的带宽。


Java使用称为压缩oops的技巧来解决这个问题。而不是指向内存中的确切字节位置,指针引用对象偏移量。这意味着一个32位指针可以引用40亿个对象,而不是40亿个字节。最终,这意味着堆可以增长到约32 GB的物理尺寸,同时仍然使用32位指针。


一旦你穿越了这个神奇的〜32 GB的边界,指针就会切换回普通的对象指针。每个指针的大小增加,使用更多的CPU内存带宽,并且实际上会丢失内存。实际上,在使用压缩oops获得32 GB以下堆的相同有效内存之前,需要大约40-50 GB的分配堆。


以上小结为:即使你有足够的内存空间,尽量避免跨越32GB的堆边界。

否则会导致浪费了内存,降低了CPU的性能,并使GC在大堆中挣扎。


8、我是内存土豪怎么办?

假设,我有一台带有1TB RAM的机器!

1

32 GB的基线相当重要。那么当你的机器有很多内存时你怎么做?当前具有512-768 GB RAM的超级服务器变得越来越普遍。


首先,我们建议避免使用这种大型机器。


但是如果你已经有了这些机器,你有三种实用的选择:


1. 你是否主要进行全文搜索?


考虑给Elasticsearch提供4-32 GB,并让Lucene通过操作系统文件系统缓存使用剩余的内存。所有内存都会缓存段,并导致快速全文搜索。


2. 你在做很多排序/聚合?


大部分聚合数字,日期,地理位置和not_analyzed字符串?你很幸运,你的聚合将在内存缓存的文档值上完成!


从4-32 GB的内存中给Elasticsearch一个地方,剩下的让操作系统在内存中缓存doc值。


3. 你是否对分析过的字符串进行了很多排序/聚合(例如对于字标记或SigTerms等)?


不幸的是,这意味着你需要fielddata,这意味着你需要堆空间。


考虑在一台机器上运行两个或多个节点,而不是一个节点数量巨大的RAM。


尽管如此,仍然坚持50%的规则。


To土豪内存小结:


因此,如果您的机器具有128 GB的RAM,请运行两个节点,每个节点的容量低于32 GB。这意味着小于64 GB将用于堆,而Lucene将剩余64 GB以上。


如果您选择此选项,请在您的配置中设置cluster.routing.allocation.same_shard.host:true。这将阻止主副本分片共享同一台物理机(因为这会消除副本高可用性的好处)。


9、堆内存优化建议

方式一:最好的办法是在系统上完全禁用交。

这可以暂时完成:


sudo swapoff -a

1

要永久禁用它,你可能需要编辑你的/ etc / fstab。


方式二:控制操作系统尝试交换内存的积极性。


如果完全禁用交换不是一种选择,您可以尝试降低swappiness。该值控制操作系统尝试交换内存的积极性。这可以防止在正常情况下交换,但仍然允许操作系统在紧急内存情况下进行交换。


对于大多数Linux系统,这是使用sysctl值配置的:


vm.swappiness = 1

1

1的swappiness优于0,因为在某些内核版本上,swappiness为0可以调用OOM杀手。


方式三:mlockall允许JVM锁定其内存并防止其被操作系统交换。


最后,如果两种方法都不可行,则应启用mlockall。文件。这允许JVM锁定其内存并防止其被操作系统交换。在你的elasticsearch.yml中,设置这个:


bootstrap.mlockall:true

1

10、注意

修改JVM相关配置很容易,但容易产生难以测量的不透明效果,并最终将您的群集解调为缓慢,不稳定的混乱

在调试群集时,第一步通常是删除所有自定义配置。大约一半的时间,仅靠这一点就恢复了稳定性和性能。

11、最新认知

wood@Ctrip

事实上,给ES分配的内存有一个魔法上限值26GB,


这样可以确保启用zero based Compressed Oops,这样性能才是最佳的。


参考:https://elasticsearch.cn/question/3995

https://www.elastic.co/blog/a-heap-of-trouble


12、小结

这是一篇官网文档&原理的整合文章,主要目的是梳理认知。


13、参考

基础:http://t.cn/RH4DDYu

设置:http://t.cn/RmKbO1i

建议:http://t.cn/RmKbjsF

注意:http://t.cn/RmKbHp5

堆:http://t.cn/RmKbRji

相关实践学习
以电商场景为例搭建AI语义搜索应用
本实验旨在通过阿里云Elasticsearch结合阿里云搜索开发工作台AI模型服务,构建一个高效、精准的语义搜索系统,模拟电商场景,深入理解AI搜索技术原理并掌握其实现过程。
ElasticSearch 最新快速入门教程
本课程由千锋教育提供。全文搜索的需求非常大。而开源的解决办法Elasricsearch(Elastic)就是一个非常好的工具。目前是全文搜索引擎的首选。本系列教程由浅入深讲解了在CentOS7系统下如何搭建ElasticSearch,如何使用Kibana实现各种方式的搜索并详细分析了搜索的原理,最后讲解了在Java应用中如何集成ElasticSearch并实现搜索。  
相关文章
|
11月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
1811 1
|
监控 Java
压力测试Jmeter的简单使用,性能监控-堆内存与垃圾回收 -jvisualvm的使用
这篇文章介绍了如何使用JMeter进行压力测试,包括测试前的配置、测试执行和结果查看。同时,还探讨了性能监控工具jconsole和jvisualvm的使用,特别是jvisualvm,它可以监控内存泄露、跟踪垃圾回收、执行时内存和CPU分析以及线程分析等,文章还提供了使用这些工具的详细步骤和说明。
压力测试Jmeter的简单使用,性能监控-堆内存与垃圾回收 -jvisualvm的使用
|
10月前
|
算法 Java
堆内存分配策略解密
本文深入探讨了Java虚拟机中堆内存的分配策略,包括新生代(Eden区和Survivor区)与老年代的分配机制。新生代对象优先分配在Eden区,当空间不足时执行Minor GC并将存活对象移至Survivor区;老年代则用于存放长期存活或大对象,避免频繁内存拷贝。通过动态对象年龄判定优化晋升策略,并介绍Full GC触发条件。理解这些策略有助于提高程序性能和稳定性。
|
10月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
239 5
|
12月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
559 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
11月前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
211 1
|
缓存 Java 测试技术
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
使用JMeter对项目各个接口进行压力测试,并对前端进行动静分离优化,优化三级分类查询接口的性能
459 10
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
|
12月前
|
算法 Java
JVM进阶调优系列(3)堆内存的对象什么时候被回收?
堆对象的生命周期是咋样的?什么时候被回收,回收前又如何流转?具体又是被如何回收?今天重点讲对象GC,看完这篇就全都明白了。
|
C++
析构造函数就是为了释放内存,就是在局部指针消失前释放内存,拷贝构造函数就是以构造函数为模块,在堆里面新开一块,同一个变量在堆里面的地址
本文讨论了C++中构造函数和析构函数的作用,特别是它们在管理动态内存分配和释放中的重要性,以及如何正确地实现拷贝构造函数以避免内存泄漏。
131 2
|
存储 程序员 编译器
堆和栈内存的区别是什么
【8月更文挑战第23天】堆和栈内存的区别是什么
1078 4

热门文章

最新文章