上一篇讲到了ES的river数据导入,但是看起来这么简单的流程也还是有一些坑,比如在我导入我司的一个3kw表内容时就碰到了整个虚拟机都卡住,几乎无法登陆的问题。

因为es和river插件都是用java写的,这种时候感觉就有点手足无措。但是在es的日志里发现了频繁GC的信息。每次垃圾回收都会持续很长时间。这种现象在Java界还有一个很有意思的称谓:

Stop the world

援引一下别人的说明:

Stop the world 机制简称STW,即,在执行垃圾收集算法时,Java应用程序的其他所有除了垃圾收集帮助器线程之外的线程都被挂起  

说起STW,只要有GC的语言都会遇到这个问题。Go在1.5之前的GC也是一直为人所诟病,而且像STW这种情况就更严重了啊,整个一台机器直接就没办法向外提供服务了。之前看到360和小米工程师在go语言早期GC不给力的时候怎么解决这种问题呢~靠重启。。你没看错,就是靠重启。

再说到前面的问题,我们只看STW的描述的话会发现:额,你这只是挂起java的线程,但为毛我虚拟机整个机器的load average都上去了,然后还登陆不上去。

原因就是跑满了cpu。

虽然你其它资源都没占满,但只要Full GC就必然会有这样的问题,为了jvm占用内存少,那么就可能要消耗更多的cpu去做GC,如果能给jvm更大的运行时内存,那么想必就可以减少Full GC的次数罢!

然后我们设置了一下river的各种内存选项(其实是从不知道哪里粘来的选项啦。。

-Xms2g -Xmx2g -Djava.awt.headless=true -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError -XX:+DisableExplicitGC -Dfile.encoding=UTF-8

这次非常地顺利,很快全部数据导入完成,可以随便折腾啦!

思想其实很朴素,用空间来换时间。

在运行es的时候其实内存设置也是一个需要注意的选项,在es的bin目录下elasticsearch.in.sh中可以ES_HEAP_SIZE,最好直接设置为整个系统内存的一半,这样效率是最高的。可以减少es的gc次数。

因为上线的时候没有改默认的内存参数,所以数据量大的时候有过一次OOM。。所以,as above。

有时间需要了解一下jvm了,虽然不是java程序员orz