Elasticsearch-107-不要随意调节JVM和Thread Pool的原因

概述

es中有很多配置我们可以去调节,但是在99.99%的情况下,对于es来说,大部分的参数保留为默认的就可以了,因为这些参数经常被滥用和错误的调节,继而导致严重的稳定性问题以及性能的急剧下降.

Jvm GC

es默认用的垃圾回收器是CMS,jvm使用垃圾回收器来释放掉不用的内存,千万不要去调节默认的垃圾回收行为.

CMS回收器是并发式的回收器,能够跟应用程序工作线程并发工作,最大程度减少垃圾回收时的服务停顿时间.但是CMS还是会有两个停顿阶段,同时在回收特别大的heap时也会有一些问题.尽管有一些缺点,但是CMS对于要求低延时请求响应的软件来说,还是最佳的垃圾回收器,因此官方的推荐就是使用CMS垃圾回收器.

有一种最新的垃圾回收器叫做G1.G1回收器可以比CMS提供更少的回收停顿时间,而且能够这对大heap有更好的回收表现.它会将heap划分为多个region,然后自动预测哪个region会有最多可以回收的空间.通过回收那些region,就可以最小化停顿时长,而且可以针对大heap进行回收.
听起来还挺不错的,但是不幸的是,G1还是比较年轻的一种垃圾回收器,而且经常会发现一些新的bug,这些bug可能会导致jvm挂掉.lucene的测试套件就检查出来了G1的一些bug.因此es官方不推荐现在使用G1垃圾回收器,也许在不久的未来,等G1更加稳定的时候,可以使用G1.

Threadpool

每个人都很喜欢去调优线程池,而且大部分人都特别喜欢增加线程池的线程数量,无论是大量的写入,还是大量的搜索,或者是感觉服务器的cpu idle空闲率太高,都会增加更多的线程.在es中,默认的threadpool设置是非常合理的,对于所有的threadpool来说,除了搜索的线程池,都是线程数量设置的跟cpu core一样多的.如果我们有8个cpu core,那么就可以并行运行8个线程.那么对于大部分的线程池来说,分配8个线程就是最合理的数量.

不过搜索会有一个更加大的threadpool,一般被配置为:cpu core * 3 / 2 + 1.

也许我们会觉得有些线程可能会因为磁盘IO等操作block住,所以我们需要更多的线程.但是在es中这并不是一个问题,大多数的磁盘IO操作都是由lucene的线程管理的,而不是由es管理的,因此es的线程不需要关心这个问题.此外,threadpool还会通过在彼此之间传递任务来协作执行,我们不需要担心某一个网络线程会因为等待一次磁盘写操作,而导致自己被block住,无法处理网络请求.网络线程可以将那个磁盘写操作交给其他线程池去执行,然后自己接着回来处理网络请求.

其实我们的进程的计算能力是有限的,分配更多的线程只会强迫cpu在多个线程上下文之间频繁来回切换.一个cpu core在同一时间只能运行一条线程,所以如果cpu要切换到另外一个线程去执行,需要将当前的state保存起来,然后加载其他的线程进来执行.如果线程上下文切换发生在一个cpu core内,那么还好一些,但是如果在多个cpu core之间发生线程上下文切换,那么还需要走一个cpu core内部的通信.这种线程上下文切换会消耗掉很多的cpu资源,对于现在的cpu来说,每次线程上下文切换,都会导致30微秒的时间开销,所以宁愿将这些时间花费在任务的处理上.

很多人会将threadpool大小设置为一些很愚蠢的数值,在一个8核的机器上,可能运行了超过60,100,甚至1000个线程.这么多的线程会导致cpu资源利用率很低.所以下次如果我们要调节线程池的话,记住,千万别这么干.如果一定要调节线程数量,也得记住要根据你的cpu core数量来调节,比如设置为cpu core的两倍,如果设置的再多,那么就是一种浪费了.