首先,作为一个JAVA应用,就脱离不开JVM和GC,因为应用层面生成大量长生命周期的对象,是给heap造成压力的主要原因,例如读取一大片数据在内存中进行排序,或者在heap内部建cache缓存大量数据。
其次, ES集群 底层存储引擎是基于Lucene的,而Lucene的倒排索引(Inverted Index)是先在内存里生成,然后定期以段文件(segment file)的形式刷到磁盘的。每个段实际就是一个完整的倒排索引,并且一旦写到磁盘上就不会做修改。 API层面的文档更新和删除实际上是增量写入的一种特殊文档,会保存在新的段里。不变的段文件易于被操作系统cache,热数据几乎等效于内存访问。
并且ES的data node存储数据并非只是耗费磁盘空间的,为了加速数据的访问,每个segment都有会一些索引数据驻留在heap里。因此segment越多,瓜分掉的heap也越多,并且这部分heap是无法被GC掉的。如长时间频繁GC就需要考虑删除、归档数据,或者扩容了。
然后就是采用G1来进行垃圾回收,因为传统GC可以说内存一大 什么都废了,主要在垃圾回收时,都会产生应用程序的停顿,停顿产生时,整个应用程序会被卡死,没有任何响应。
java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于gc引起。而G1相对于传统GC来说最大进步就是STW可控,虽然各个Region所属区域是动态变化的,但不是随意变化的,还是会为Eden、Survivor、老年代保留各自需要的空间。例如不会让Eden空间的分配超过系统设定的值等。
这里直接可修改配置文件/home/server66/usr/local/es/config/ jvm.options添加对应参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis=50