原文链接:
http://jprante.github.com/2012/11/28/Elasticsearch-Java-Virtual-Machine-settings-explained.html
从2006年的java6 到现在java7无论是性能或其它方面都有了很大的改进,我们没有理由不在使用Java7,我个人也认为java7在内存方面比java6优秀.
这使我有对java6和java7及es在jvm设置有了很大的趣兴,因此写一篇博文一探其中之道。
Es已经预先为我们的JVM进行了一些设置,而且这些设置都是比较好的,现在这方面的设置也非常小心,因此你不需要关心jvm的设置就可以马上使用ES,这大概就是所谓的开箱即使吧。
但我们也可能jvm进行一些自己的设置,以使其能被监测或是改善你的ES Cluster中的node的一些性能。
这篇博文试图阐明ES中的预配置和讨论最常见的一些调整,最后给出如何进行调优。
ES JVM 设置
JVM参数 |
ES默认值 |
环境变量名 |
||
-Xms |
256m |
|
||
-Xmx |
1g |
|
||
-Xms and –Xmx |
|
|
||
-Xmn |
|
|
||
-XX:MaxDirectMemorySize |
|
|
||
-Xss |
256k |
|
||
-XX:UseParNewGC |
+ |
|
||
-XX:UseConcMarkSweepGC |
+ |
|
||
|
75 |
|
||
-XX:UseCMSInitiatingOccupancyOnly |
|
|
||
-XX:UseCondCardMark |
|
|
我们可以注意到ES JVM Heap内存设置为在256M在1GB之间.
这个设置是为在开发和示范环境中使用的,开发人员可以通过简单地安装ES就可以使用了,但是这样的内存设置在很多情况下都是不够用的,我在需要设置更大的值。
(JVM)
ES_MIN_MEM/ES_MAX_MEM 用于控制jvm的堆内存,另外还有ES_HEAP_SEIZ,这样我可以设置更多的堆内存用于ES,另外建议不在启动内存堆平衡,因为这样会浪费很大的性能。
ES_HEAP_NEWSIZE这个参数用于控制堆内存的子集,即新生代堆控制
ES_DIRECT_SIZE,我们可以对应到Direct Memory Size这个参数,在JVM管理数据中使用的是NIO,本机内存可以映射到虚拟地址空间,在X64的架构上更有效,在ES中没有选择进行设置,但是有一个问题,本机直接内存的分配不会受到Java堆大小的限制,但是即然是内存那肯定还是要受到本机物理内存(包括SWAP区或者Windows虚拟内存)的限制的,一般服务器管理员配置JVM参数时,会根据实际内存设置-Xmx等参数信息,但经常忽略掉直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),而导致动态扩展时出现OutOfMemoryError异常。
下面例出一些JVM参数设置
JVM parameter Garbage collector
-XX:+UseSerialGC serial collector
-XX:+UseParallelGC parallel collector
-XX:+UseParallelOldGC Parallel compacting collector
-XX:+UseConcMarkSweepGC Concurrent-Mark-Sweep ( CMS ) collector
-XX:+UseG1GC Garbage-First collector (G1)
UseParNewGC和UseConcMarkSweepGC是结并并行和行发性的垃圾回收机制,在JAVA6中将默认为UserParNewGC和UseGoncMarkSweepGC并禁用串行收集器.
CMSInitiatingOccupancyFraction 垃圾回收,这个75是指,到heap占用到75%时开发进行清理,我们知道堆分为新生代和老年代两块可新生代一块为老年代的两倍,也许在没有达到75%时也可能进行垃圾回收。
UseCondCardMark 将在在高度并发的情况下,将些值注释掉
总结:
1、修改MAX 和MIN Heap大小设置。
2、设置垃圾回收百分比
3、如果在JAVA7中禁用默认的G1垃圾回收机制。
JVM进程的内存结构
JVM内存分为如下几段:
JVM CODE用于内部代码存放
Noe-heap memory用于加载类
Stack memory 用于存放本地变量和线程操作数
Heap memory 存放引用类型对象
Direct Buffer,缓冲输入,输出数据
Heap memory大小设置是非常重要的,因为java的运行取决于一个合理的heap的大小,如果设置太小,在许多垃圾回收或是高性能的情况下就会出现OutOfMemory异常。如果堆太大,垃圾回收将需要更大的数据,该算法将要面对更高数量的存活堆,这样操作系统也会面对较大的压力。
Non-heap内存分配是由java应用程序自动设置的,没有办法控制这个参数,因为它是由JAVA应用程序代码决定的。
垃圾回收与Lucene段
在ES中的垃圾回收器是集用的CMS垃圾回收,这种回收器不是提高敢回收的效率可是降低了回收的次数,但是面对比较大的数据集合时,这种回收可能需要的时间更长。
而这种大的数据集合主要是在Lucene的索引中,因些可以将索引的段进行一行调优工作,提高GC的效率。
index.merge.policy.segments_per_tier
减少分页
在大堆内存的情况下,如果内存不足时会与操作系统的SWAP空间进行分页数据的交换,但是这种交换是非常慢的,这种会降低整体性能。
垃圾回收器的选择
JAVA 7中的默认是G1垃圾回收器,这种回收器和CMS回收相对,他在于处理吞吐量,但是如果在大堆的情况下CMS回收器在性能上将超过G1.
性能调优策略
1、 收集日志
2、 对日志进行分析
3、 选择你要优化的目标
4、 计划优化
5、 应用新有设置
6、 监控程序在新设置后的运行情况
7、 反复试尝
ES 垃圾回收日志格式
将日志等级调用警告在垃圾回收时你能看到如下信息:
[2012-11-26 18:13:53,166][WARN ][monitor.jvm ] [Ectokid] [gc][ParNew][1135087][11248] duration [2.6m], collections [1]/[2.7m], total [2.6m]/[6.8m], memory [2.4gb]->[2.3gb]/[3.8gb], all_pools {[Code Cache] [13.7mb]->[13.7mb]/[48mb]}{[Par Eden Space] [109.6mb]->[15.4mb]/[1gb]}{[Par Survivor Space] [136.5mb]->[0b]/[136.5mb]}{[CMS Old Gen] [2.1gb]->[2.3gb]/[2.6gb]}{[CMS Perm Gen] [35.1mb]->[34.9mb]/[82mb]}
LogFile |
说明 |
Gc |
垃圾回收运行 |
ParNew |
新生代垃圾回收器 |
duration 2.6m |
垃圾回收花费时间 |
collections [1]/[2.7m] |
一个收集器运行花费2.7M |
memory [2.4gb] |
预设2.4GB |
[2.3gb]/[3.8gb] |
现在使用2.3GB/总共3.8GB |
Code Cache [13.7mb]->[13.7mb]/[48mb] |
代码缓存 |
Par Eden Space [109.6mb]->[15.4mb]/[1gb] |
Par Eden Space使用空间 |
Par Survivor Space[136.5mb]->[0b]/[136.5mb] |
Par Survivor Space |
CMS Old Gen [2.1gb]->[2.3gb]/[2.6gb] |
CMS Old Gen |
CMS Perm Gen [35.1mb]->[34.9mb]/[82mb] |
CMS Perm Gen |
建议:
1、ES不要运行在6U22之前因之多版本的JDK存在许多的bug,尽量使用Sun/Oracle比较最出的JDK6-7因为里面修复很多bug.
如果在JAVA7正式发布的情况下最好使用JDK7(不过要到2013了)
2、考虑到ES是一个比较新的软件,利用最先的技术来获取性能,尽量从JVM中来挤压性能,另外检索您的操作系统是否是最新版的,尽量使用最新版的操作系统。
3、做好随时更新JAVA版本和ES的版本的情况,因为每季度或是每年都会有新的版本出来。所以在做好版本更新的准备
4、测试从小到大,因为ES的强在多个节点的部署,一个节点是不足以测试出其性能,一个生产系统至少在三个节点以上。
5、测试JVM
6、如果索引有更新请记住对索引段的操作(index.merge.policy.segments_per_tier)
7、在性能调优之前,请先确定系统的最大性能和最大吞吐量
8、启用日志记录对JAVA垃圾回怍机制,有助于更好的诊断,以至于来调整你的系统
9、提高CMS垃圾收集器,您可以添加一个合理的- xx:CMSWaitDuration参数
10、如果堆大小趣过6-8GB,请选择使用CMS