Elasticsearch 的内存优化

找到一篇之前自己总结的 es 内存优化的观察记录,发出来分享保存一下,希望可以对大家有所帮助和启发

关于 ES 选择垃圾收集器

CMS 和 G1
大内存机器( 大于 8 G )建议使用 G1 。

G1 (425 次 young gc)

CMS (1960 次 young gc)

G1 (一夜过后增长到 600 次)

下图 5 s 间隔

CMS (一夜过后增长到 2713 次)

从增长量来看
(2713-1960)/(600-425) = 753 / 175 = 4.3 倍
总时长 9 :75 。CMS 是 G1 的 8 倍

JVM 配置

Java 版本为 openjdk version “11.0.9” 2020-10-20 LTS

CMS 机器配置:

VM Flags:
-XX:+AlwaysPreTouch -XX:CICompilerCount=15 -XX:CMSInitiatingOccupancyFraction=75 -XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/elasticsearch -XX:InitialHeapSize=33285996544 -XX:MaxDirectMemorySize=16642998272 -XX:MaxHeapSize=33285996544 -XX:MaxNewSize=2006515712 -XX:MaxTenuringThreshold=6 -XX:MinHeapDeltaBytes=196608 -XX:MinHeapSize=33285996544 -XX:NewSize=2006515712 -XX:NonNMethodCodeHeapSize=8182140 -XX:NonProfiledCodeHeapSize=121738050 -XX:OldSize=31279480832 -XX:-OmitStackTraceInFastThrow -XX:ProfiledCodeHeapSize=121738050 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:SoftMaxHeapSize=33285996544 -XX:ThreadStackSize=1024 -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC

目前 老年代 30G 年轻代 2 G 建议可以适当调大年轻代大小,没看到指定元空间大小,建议 256 或者 512
所以为什么 CMS 看起来堆内存空间波动这么小,是因为他年轻代就只有 2 G ,超出阈值直接触发 young gc ,所以看起来是波动小 gc 频繁

G1 机器配置(这里推荐 G1):

VM Flags:
-XX:+AlwaysPreTouch -XX:CICompilerCount=15 -XX:ConcGCThreads=6 -XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log -XX:G1ConcRefinementThreads=23 -XX:G1HeapRegionSize=8388608 -XX:G1ReservePercent=25 -XX:GCDrainStackTargetSize=64 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/elasticsearch -XX:InitialHeapSize=33285996544 -XX:InitiatingHeapOccupancyPercent=45 -XX:MarkStackSize=4194304 -XX:MaxDirectMemorySize=16642998272 -XX:MaxHeapSize=33285996544 -XX:MaxNewSize=11089739776 -XX:MinHeapDeltaBytes=8388608 -XX:MinHeapSize=33285996544 -XX:NewRatio=2 -XX:NonNMethodCodeHeapSize=8182140 -XX:NonProfiledCodeHeapSize=121738050 -XX:-OmitStackTraceInFastThrow -XX:ProfiledCodeHeapSize=121738050 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:SoftMaxHeapSize=33285996544 -XX:ThreadStackSize=1024 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC
VM Arguments:
jvm_args: -Xms31g -Xmx31g -XX:+UseG1GC -XX:NewRatio=2 -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=45 -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dio.netty.allocator.numDirectArenas=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Djava.io.tmpdir=/tmp/elasticsearch-11678995370584773542 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/elasticsearch -XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=/var/log/elasticsearch/gc.log:utctime,pid,tags:filecount=32,filesize=64m -Djava.locale.providers=COMPAT -Dio.netty.allocator.type=pooled -XX:MaxDirectMemorySize=16642998272 -Des.path.home=/usr/share/elasticsearch -Des.path.conf=/etc/elasticsearch -Des.distribution.flavor=default -Des.distribution.type=rpm -Des.bundled_jdk=true

目前设置为 堆大小 31 G (32 G 会取消指针压缩这个影响会很大,32G 以上寻址没法压缩,一个问题,理论上等于 32G 也可以指针压缩吧?可能会可能不会,JVM 具体实现不同可能这个阈值的真值不同,所以 31 G 最稳妥)设置了 -XX:NewRatio=2 新老比为 1:2
新生代大小约 10G 老年代大小约 20G
目前看来 每次 young gc 后仍会有少量对象进入老年代,老年代已用 10.5 G
建议可以使用默认值 年轻代最大 60% 即 18.6G 老年代 12.4G。观察老年代是否趋于平衡
建议设置元空间大小 512M OR 256M
165 s 一次 yang gc old 涨幅 2174 kb ~ 2M 920 1M 假设取 1.5M
即每 1500/165~9 约每秒 9kb777mb 每天 约 12 天一次 mixed gc
目前看来 ES 正常,之前可能是指针压缩的问题
-XX:G1HeapRegionSize=8388608,分区数 3968 个 Region 8M Humongous 对象过多,建议扩充一倍,或者使用默认分片数量 2048 。


G1 执行 GC 清理 old user :12G(清理前) mixed gc 后 9.2 G

CMS 执行 full gc 15G -> 6.8 G


这里引发一个问题,ES 堆里都放了些什么?

在索引创建的时候会默认创建 倒排索引和正排索引 内存足够会缓存到 cache 里 ES 使用 倒排索引+正排索引 实现聚合,比如查找 名称带有 苹果 的数据并 以 颜色字段分组聚合。

考虑聚合查询的场景对应字段打开 doc_value 正排索引。否则 filedata load 内存消耗会比较大。 这里考虑了一下 应该是默认会创建 doc_value 实际在查询对应信息的时候也不是 doc_value 占用内存

内存占用分布

ES 的 Heap 内存基本上被
Segment Memory、
Filter Cache、
Field Data Cache、
Bulk Queue、
Indexing Buffer、
Cluster State Buffer、
各类聚合查询的结果集fetch所消耗掉

1、Segment Memory

ES 的 data node 存储数据并非只是耗费磁盘空间的,为了加速数据的访问,每个segment都有会一些索引数据驻留在 heap 里。因此 segment 越多,瓜分掉的 heap 也越多,并且这部分 heap 是无法被 GC 掉的! 理解这点对于监控和管理集群容量很重要,当一个 node的 segment memory 占用过多的时候,就需要考虑删除、归档数据,或者扩容了。

常驻内存。
查看一个node上所有segment占用的memory总和
GET _cat/nodes?v&h=name,port,sm

2、Filter Cache
Filter cache 是用来缓存使用过的 filter 的结果集的,需要注意的是这个缓存也是常驻heap,无法GC的。默认 10% heap size 设置,如果实际使用中heap没什么压力的情况下,才考虑加大这个设置。

3、Field Data Cache
对搜索结果做排序或者聚合操作,需要将倒排索引里的数据进行解析,然后进行一次倒排。在有大量排序、数据聚合的应用场景,可以说 field data cache 是性能和稳定性的杀手。这个过程非常耗费时间
ES2.0以后,正式默认启用Doc Values特性,避免使用 Field Data Cache

4、Bulk Queue
Bulk Queue是做什么用的?当所有的bulk thread都在忙,无法响应新的bulk request的时候,将request在内存里排列起来,然后慢慢清掉。一般来说,Bulk queue不会消耗很多的heap,但是见过一些用户为了提高bulk的速度,客户端设置了很大的并发量,并且将bulk Queue设置到不可思议的大,比如好几千。这在应对短暂的请求爆发的时候有用,但是如果集群本身索引速度一直跟不上,设置的好几千的queue都满了会是什么状况呢? 取决于一个bulk的数据量大小,乘上queue的大小,heap很有可能就不够用,内存溢出了。一般来说官方默认的thread
pool设置已经能很好的工作了,建议不要随意去“调优”相关的设置,很多时候都是适得其反的效果。

5、Indexing Buffer
Indexing Buffer是用来缓存新数据,当其满了或者refresh/flush interval到了,就会以segment file的形式写入到磁盘。这个参数的默认值是10% heap size。根据经验,这个默认值也能够很好的工作,应对很大的索引吞吐量。但有些用户认为这个buffer越大吞吐量越高,因此见过有用户将其设置为40%的。到了极端的情况,写入速度很高的时候,40%都被占用,导致OOM。

Cluster State Buffer
ES被设计成每个Node都可以响应用户的api请求,因此每个Node的内存里都包含有一份集群状态的拷贝。这个Cluster state包含诸如集群有多少个Node,多少个index,每个index的mapping是什么?有少shard,每个shard的分配情况等等(ES有各类stats api获取这类数据)。在一个规模很大的集群,这个状态信息可能会非常大的,耗用的内存空间就不可忽视了。并且在ES2.0之前的版本,state的更新是由Master Node做完以后全量散播到其他结点的。频繁的状态更新都有可能给heap带来压力。在超大规模集群的情况下,可以考虑分集群并通过tribe node连接做到对用户api的透明,这样可以保证每个集群里的state信息不会膨胀得过大。

超大搜索聚合结果集的fetch
ES 是分布式搜索引擎,搜索和聚合计算除了在各个 data node 并行计算以外,还需要将结果返回给汇总节点进行汇总和排序后再返回。无论是搜索,还是聚合,如果返回结果的 size 设置过大,都会给 heap 造成很大的压力,特别是数据汇聚节点。

ES 集群配置

bootstrap.memory_lock=true 内存锁,生产环境无脑设为 true 会锁内存,内存不足时会使用 swap 内存空间,其性能极差

JVM 常用命令

top
top -p [pid] 键入 H 查看进程线程情况

jmap

jmap -histo [pid] > log.txt 查看内存信息,实例个数以及占用内存大小 注意导出太大问题
jmap -heap [pid] 堆信息
jmap ‐dump:format=b,file=eureka.hprof [pid] 堆内存 dump 注意导出太大问题

jstack

jstack [pid] 查找死锁

jinfo

jinfo -flags [pid] 查看正在运行的 Java 应用程序的扩展参数
jinfo -sysprops [pid] 查看 Java 系统参数

jstat

jstat -gc [pid] 堆 gc 回收情况
jstat -gccapacity [pid] 查看堆内存统计

jstat -gcnew [pid] 查看新生代 gc 回收情况
jstat -gcold [pid] 查看老年代 gc 回收情况

jstat -gcnewcapacity [pid] 查看新生代内存统计
jstat -gcoldcapacity [pid] 查看老年代内存统计

jstat -gcmetacapacity [pid] 查看元空间统计

jstat -gcutil [pid] 查看各区域使用比例

最主要的危险操作是下面这三种:

  1. jmap -dump
    这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。

  2. jmap -permstat
    这个命令执行,JVM会去统计perm区的状况,这整个过程也会比较的耗时,并且同样也会暂停应用。

  3. jmap -histo:live
    这个命令执行,JVM会先触发 full gc,然后再统计信息。
    jmap -histo:live 22078 |more

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

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

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

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

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

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

堆内存为什么不能超过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在大堆中挣扎。

Elasticsearch 的内存优化相关推荐

  1. 腾讯万亿级Elasticsearch应用及优化解密

    Elasticsearch(ES)作为开源首选的分布式搜索分析引擎,通过一套系统轻松满足用户的日志实时分析.全文检索.结构化数据分析等多种需求,大幅降低大数据时代挖掘数据价值的成本. 腾讯在公司内部丰 ...

  2. Elasticsearch 检索性能优化实战指南

    1.当我们在说 Elasticsearch 检索性能优化的时候,实际在说什么?! 检索响应慢! 并发检索用户多时,响应时间不达标 卡死了! 怎么还没有出结果? 怎么这么慢? 为啥竞品产品的很快就返回结 ...

  3. 深度学习框架的内存优化机制

    深度学习框架的内存优化机制 https://www.cnblogs.com/DicksonJYL/p/9576896.html 这篇博文简单介绍下深度学习框架的内存优化方式,主要参考资料1,也就是MX ...

  4. Android优化之内存优化倒计时篇

    本文来自网易云社区 作者:聂雷震 本篇文章介绍的内容是如何在安卓手机上实现高效的倒计时效果,这个高效有两个标准:1.刷新频率足够高,让用户觉得这个倒计时的确是倒计时,而不是幻灯片:2.不能占用太多的内 ...

  5. ANDROID内存优化(大汇总——中)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...

  6. JVM 内存优化设置

    from:http://blog.sina.com.cn/s/blog_707577700100vy4m.html 在一些规模稍大的应用中,Java虚拟机(JVM)的内存设置尤为重要,想在项目中取得好 ...

  7. Android内存优化(三)避免可控的内存泄漏

    相关文章 Android性能优化系列 Java虚拟机系列 前言 内存泄漏向来都是内存优化的重点,它如同幽灵一般存于我们的应用当中,有时它不会现身,但一旦现身就会让你头疼不已.因此,如何避免.发现和解决 ...

  8. SQL Server 2014 内存优化表(1)实现内存优化表

    内存优化表(Memory-Optimized Tables)是SQL Server 2014的新特性,目前仅适用于评估版(Evaluation Edition).开发版(Developer Editi ...

  9. Redis学习-内存优化

    以下为个人学习Redis的备忘录--内存优化,基于Redis4.0.2 1.随时查看info memory,了解内存使用状况: 127.0.0.1:6379> info memory # Mem ...

  10. Android的内存优化

    腾讯公司在五月三十一日开展[腾讯Bugly移动开发人员沙龙]大会.大会上面叶方正老师解说了 关于Android的内存优化的问题,只是我感觉叶老师许多其它的站在了測试的角度上去解释了这一方面,叶老师给我 ...

最新文章

  1. 初识C语言---(4)
  2. Java编码技巧之高效代码50例
  3. Kinect for windows的脸部识别
  4. 什么叫一年有四季......
  5. linux分区个数,Linux分区个数限制
  6. html 图片 把绝对路径改为相对路径,html中想把图片绝对路径 改成相对路径怎么操作?...
  7. 在同时使用animation和translate时,translate无效
  8. Python中Image缩放、旋转、翻转等操作
  9. matlab 加随机数,随机数加上100:Matlab
  10. 自己写的BMFont导入工具,快速把图片转换为美术字体
  11. 小米官网竖直导航栏html,小米官网css3导航菜单代码_html/css_WEB-ITnose
  12. JPG图片转换成Word文字教程分享
  13. 如何在Word中重置用户选项和注册表设置
  14. 基于ERNIR3.0文本分类:(KUAKE-QIC)意图识别多分类(单标签)
  15. 奇怪的小鸭子也增加了Java实现
  16. 43岁,外企经理,公司不和我续签了
  17. 看不见的竞争 带宽优化
  18. 以太坊源码学习(一) 正本清源
  19. 大型网络游戏服务器的框架设计(一)
  20. LINGO实例,优化问题1

热门文章

  1. 电容去耦原理笔记(彻底理解并伴有公式计算)
  2. html5图片做成简单拼图,html5版canvas自由拼图实例_html5教程技巧
  3. 【FXCG】如何计算投资组合 Beta?
  4. 面试知识储备:新浪微博Android客户端的实现
  5. 《花花公子》的封面女郎,计算机图像界的女神
  6. 基于javaweb的文具学习用品商城系统(java+ssm+jsp+jquery+mysql)
  7. 计算机毕业设计ssm线上学习系统8e88w系统+程序+源码+lw+远程部署
  8. 为什么管理创新总是发生在汽车行业?
  9. java 调用百度语音
  10. 2020 1月 月末总结