Elasticsearch性能调优:千万不要做愚蠢的事

在 Elasticsearch 中有一些热点,人们可能不可避免的会碰到。 我们理解的,所有的调整就是为了优化,但是这些调整,你真的不需要理会它。因为它们经常会被乱用,从而造成系统的不稳定或者糟糕的性能,甚至两者都有可能。

原文链接:不要触碰这些配置

官方文档参考:正确配置线程池

垃圾回收器

先说结论,

不要更改默认的垃圾回收器!

Elasticsearch 默认的垃圾回收器( GC )是 CMS。 这个垃圾回收器可以和应用并行处理,以便它可以最小化停顿。 然而,它有两个 stop-the-world 阶段,处理大内存也有点吃力。

尽管有这些缺点,它还是目前对于像 Elasticsearch 这样低延迟需求软件的最佳垃圾回收器。官方建议使用 CMS。

现在有一款新的垃圾回收器,叫 G1 垃圾回收器( G1)。 这款新的 GC 被设计,旨在比 CMS 更小的暂停时间,以及对大内存的处理能力。 它的原理是把内存分成许多区域,并且预测哪些区域最有可能需要回收内存。通过优先收集这些区域( garbage first ),产生更小的暂停时间,从而能应对更大的内存。

听起来很棒!遗憾的是,G1 还是太新了,经常发现新的 bugs。这些错误通常是段( segfault )类型,便造成硬盘的崩溃。 Lucene 的测试套件对垃圾回收算法要求严格,看起来这些缺陷 G1 并没有很好地解决。

我们很希望在将来某一天推荐使用 G1,但是对于现在,它还不能足够稳定的满足 Elasticsearch 和 Lucene 的要求。

线程池大小

Elasticsearch线程池概述

Elasticsearch运维中可以使用REST API_nodes/stats获取线程池的大小。

GET _nodes/stats
"thread_pool" : {
   "bulk" : {
     "threads" : 0,
     "queue" : 0,
     "active" : 0,
     "rejected" : 0,
     "largest" : 0,
     "completed" : 0
   },  
   "index" : {
     "threads" : 0,
     "queue" : 0,
     "active" : 0,
     "rejected" : 0,
     "largest" : 0,
     "completed" : 0
   },   
   "search" : {
     "threads" : 0,
     "queue" : 0,
     "active" : 0,
     "rejected" : 0,
     "largest" : 0,
     "completed" : 0
   },
 }

说明:以上接口返回结果只保留了具有代表性的部分,还可以使用_cat/thread_pool?format=json&pretty获取,但结果会稍有变化。

GET _cat/thread_pool?format=json&pretty
[
  {
    "node_name" : "node1",
    "name" : "index",
    "active" : "0",
    "queue" : "0",
    "rejected" : "0"
  },
  {
    "node_name" : "node1",
    "name" : "listener",
    "active" : "0",
    "queue" : "0",
    "rejected" : "0"
  },
  {
    "node_name" : "node1",
    "name" : "search",
    "active" : "0",
    "queue" : "0",
    "rejected" : "0"
  }
]

对于运维来讲,最需要关注的是rejected。当某个线程池active==threads时,表示所有线程都在忙,那么后续新的请求就会进入queue中,即queue>0,一旦queue大小超出限制,如bulk的queue默认50,那么elasticsearch进程将拒绝请求(返回HTTP状态码429),相应的拒绝次数就会累加到rejected中。

解决方法有两种:
1、记录失败的请求并重发
2、减少并发写的进程个数,同时加大每次bulk请求的size

Elasticsearch核心线程池有index、search、get、bulk等,具体作用如下。

  • index:此线程池用于索引和删除操作。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为300。
  • search:此线程池用于搜索和计数请求。它的类型默认为fixed,size默认为可用处理器的数量乘以3,队列的size默认为1000。
  • suggest:此线程池用于建议器请求。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为1000。
  • get:此线程池用于实时的GET请求。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为1000。
  • bulk:此线程池用于批量操作。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为50。
  • percolate:此线程池用于预匹配器操作。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为1000。

其中的线程池类型cache和fixed含义如下。

  • cache
    无限制的线程池,为每个请求创建一个线程。
  • fixed
    有着固定大小的线程池,大小由size属性指定,允许你指定一个队列(使用queue_size属性指定)用来保存请求,直到有一个空闲的线程来执行请求。如果Elasticsearch无法把请求放到队列中(队列满了),该请求将被拒绝。
调整方法

1.修改配置文件elasticsearch.yml

threadpool.index.type: fixed
threadpool.index.size: 100
threadpool.index.queue_size: 500

2.REST API

curl -XPUT 'localhost:9200/_cluster/settings' -d '{
    "transient": {
        "threadpool.index.type": "fixed",
        "threadpool.index.size": 100,
        "threadpool.index.queue_size": 500
    }
}'
调整线程池大小,真有必要?

同样先说结论,

请不要调整线程池的线程数。如果你真 想调整 , 一定要关注你的 CPU 核心数,最多设置成核心数的两倍,再多了都是浪费。

对于线程池的调整原理,可参考数据库连接池大小的调整原理,其基本结论就是,池的大小跟CPU核心数息息相关,通常不要高于2*CPU核心数,过高就会产生反作用。
数据库连接池和线程池到底应该设多大?这篇文章可能会颠覆你的认知

许多人 喜欢 调整线程池。 无论什么原因,人们都对增加线程数无法抵抗。索引太多了?增加线程!搜索太多了?增加线程!节点空闲率低于 95%?增加线程!

Elasticsearch 默认的线程设置已经是很合理的了。对于所有的线程池(除了 搜索 ),线程个数是根据 CPU 核心数设置的。 如果你有 8 个核,你可以同时运行的只有 8 个线程,只分配 8 个线程给任何特定的线程池是有道理的。

搜索线程池设置的大一点,配置为int(( 核心数 * 3 )/ 2 )+ 1

你可能会认为某些线程可能会阻塞(如磁盘上的 I/O 操作),所以你才想加大线程的。对于 Elasticsearch 来说这并不是一个问题:因为大多数 I/O 的操作是由 Lucene 线程管理的,而不是 Elasticsearch。

此外,线程池通过传递彼此之间的工作配合。你不必再因为它正在等待磁盘写操作而担心网络线程阻塞, 因为网络线程早已把这个工作交给另外的线程池,并且网络进行了响应。

最后,你的处理器的计算能力是有限的,拥有更多的线程会导致你的处理器频繁切换线程上下文。 一个处理器同时只能运行一个线程。所以当它需要切换到其它不同的线程的时候,它会存储当前的状态(寄存器等等),然后加载另外一个线程。 如果幸运的话,这个切换发生在同一个核心,如果不幸的话,这个切换可能发生在不同的核心,这就需要在内核间总线上进行传输。

这个上下文的切换,会给 CPU 时钟周期带来管理调度的开销;在现代的 CPUs 上,开销估计高达 30 μs。也就是说线程会被堵塞超过 30 μs,如果这个时间用于线程的运行,极有可能早就结束了。

人们经常稀里糊涂的设置线程池的值。8 个核的 CPU,我们遇到过有人配了 60、100 甚至 1000 个线程。 这些设置只会让 CPU 实际工作效率更低。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值