概述

每个Elasticsearch节点内部都维护着多个线程池,如index、search、get、bulk等,用户可以修改线程池的类型和大小,以及其他的比如reflesh, flush,warmer 等。
ElasticSearch里面各种操作都是基于线程池+回调实现的。get、search、write、index、flush等各种操作是交由这些线程池实现的。为什么定义不同类型的线程池呢?举个最简单的例子:程序里面有IO密集型任务,也有CPU密集型任务,这些任务都提交到一个线程池中执行?还是根据任务的执行特点将CPU密集型的任务都提交到一个线程池,IO密集型任务都提交到另一个线程池执行?
不同种类的操作(index、search)交由不同类型的线程池执行是有很多好处的:

  • 互不影响:index操作频繁时,并不会影响search操作的执行。
  • 资源合理利用(提升性能):如果只有一个线程池来处理所有的操作,线程池队列长度配置为多大合适?线程的数量配置多少合适?这些操作难道都要共用一个拒绝策略吗?线程执行过程中出现异常了,针对不同类型的操作,异常处理方案也是不一样的,显然:只有一个线程池(或者说只有一种类型的线程池),是无法满足这些需求的。

ES默认search线程大小为((核心数 * 3) / 2) + 1,线程设置过小导致程序崩溃。同时需要满足:不允许bulk和’indexing’线程池的大小大于CPU内核数。

核心线程池

线程池 描述
generic 通用操作,如node discovery。它的类型默认为cached。
index 此线程池用于索引和删除操作。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为200。
search 此线程池用于搜索和计数请求。它的类型默认为fixed,size默认为(可用处理器的数量* 3) / 2) + 1,队列的size默认为1000。
suggest 此线程池用于建议器请求。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为1000。
get 此线程池用于实时的GET请求。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为1000。
bulk 此线程池用于批量操作。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为50。
percolate 此线程池用于预匹配器操作。它的类型默认为fixed,size默认为可用处理器的数量,队列的size默认为1000。

线程池类型

1. cached

无限制的线程池,为每个请求创建一个线程。这种线程池是为了防止请求被阻塞或者拒绝,其中的每个线程都有一个超时时间(keep_alive),默认5分钟,一旦超时就会回收/终止。elasticsearch的generic线程池就是用该类型。注意:5.0.0-alpha2版本中废弃了该类型的线程池。

  1. threadpool:
  2. generic:
  3. keep_alive: 2m

2. fixed

固定大小的线程池,大小由size属性指定,默认是5*cores数,允许指定一个队列(使用queue_size属性指定,默认是-1,即无限制)用来保存请求,直到有一个空闲的线程来执行请求。如果Elasticsearch无法把请求放到队列中(队列满了),该请求将被拒绝。

  1. thread_pool:
  2. write:
  3. size: 30
  4. queue_size: 1000

3. fixed_auto_queue_sizeedit

该fixed_auto_queue_size线程池拥有的线程固定大小来处理与有界队列中的请求待处理那些没有线程来服务他们的请求。它类似于fixed线程池,但是会queue_size 根据基于利特尔定律的计算自动进行调整 。queue_size每次auto_queue_frame_size操作完成后,这些计算将有可能向上或向下调整50 。注意:不推荐使用,不推荐使用实验fixed_auto_queue_size线程池类型,并将在8.0中删除。

  1. thread_pool:
  2. search:
  3. size: 30
  4. queue_size: 500
  5. min_queue_size: 10
  6. max_queue_size: 1000
  7. auto_queue_frame_size: 2000
  8. target_response_time: 1s

4. scaling

可变大小的pool,大小根据负载在1到size间,同样keep_alive参数指定了闲置线程被回收的时间。

  1. thread_pool:
  2. warmer:
  3. core: 1
  4. max: 8
  5. keep_alive: 2m

线程池配置

方式1:elasticsearch.yml

  1. ################# index相关配置 #################
  2. threadpool.index.type: fixed
  3. threadpool.index.size: 100
  4. threadpool.index.queue_size: 500
  5. ################# bulk相关配置 #################
  6. thread_pool.write.size: 5
  7. thread_pool.write.queue_size: 1000
  8. ################# search相关配置 #################
  9. # queue_size允许控制没有线程执行它们的挂起请求队列的初始大小
  10. thread_pool.search.queue_size: 500
  11. # size参数控制线程数,默认为核心数乘以5
  12. thread_pool.search.size: 200
  13. # min_queue_size设置控制queue_size可以调整到的最小量
  14. thread_pool.search.min_queue_size: 10
  15. # max_queue_size设置控制queue_size可以调整到的最大量
  16. thread_pool.search.max_queue_size: 1000
  17. # auto_queue_frame_size设置控制在调整队列之前进行测量的操作数
  18. # 它应该足够大,以便单个操作不会过度偏向计算
  19. thread_pool.search.auto_queue_frame_size: 2000
  20. # target_response_time是时间值设置,指示线程池队列中任务的目标平均响应时间
  21. # 如果任务通常超过此时间,则将调低线程池队列以拒绝任务
  22. thread_pool.search.target_response_time: 6s

方式2:Rest API

  1. curl -XPUT 'localhost:9200/_cluster/settings' -d '{
  2. "transient": {
  3. "threadpool.index.type": "fixed",
  4. "threadpool.index.size": 100,
  5. "threadpool.index.queue_size": 500
  6. }
  7. }'

注意:从ElasticSearch5.0 开始,无法通过api更改线程池,需更改elasticsearch.yml并重启才能生效。

线程池查询

1. 通用查询

通过使用_cat可以查看支持的命令。

  1. curl localhost:9200/_cat
  • verbose

每个命令都支持使用?v参数,来显示详细的信息:

  1. curl localhost:9200/_cat/master?v
  • help

每个命令都支持使用help参数,来输出可以显示的列:

  1. curl localhost:9200/_cat/master?help
  • headers

通过h参数,可以指定输出的字段:

  1. curl localhost:9200/_cat/master?h=host,ip,node
  • pretty

设置pretty参数,将以简约风格输出:

  1. curl localhost:9200/_cat/master?pretty

2. 查看当前线程池状态

  1. curl -XGET 'http://localhost:9200/_nodes/stats?pretty'
  2. curl localhost:9200/_nodes/stats?pretty

当某个线程池active==threads时,表示所有线程都在忙,那么后续新的请求就会进入queue中,即queue>0,一旦queue大小超出限制,如bulk的queue默认50,那么elasticsearch进程将拒绝请求(碰到bulk HTTP状态码429),相应的拒绝次数就会累加到rejected中。
解决方案:
1、记录失败的请求并重发
2、减少并发写的进程个数,同时加大每次bulk请求的size

  1. GET /_nodes/thread_pool
  2. curl localhost:9200/_nodes/thread_pool?pretty

3. 查看线程池状态

指令可以展示 ES 自运行以来的线程池统计信息。有些信息是实时的(如active),有些信息是累计的(例如 rejected)。

  1. GET /_cat/thread_pool
  2. curl localhost:9200/_cat/thread_pool

展示特定线程池的统计信息:

  1. GET /_cat/thread_pool/search?v&h=id,name,active,queue,rejected,completed
  2. curl localhost:9200/_cat/thread_pool/search?v&h=id,name,active,queue,rejected,completed

总结

Elasticsearch的线程池其实就是对java自带的进行封装,虽然用户可以更改相关配置,但官方强烈不建议去修改默认值

参考

简书:ElasticSearch连接池的实现(Java)
https://www.jianshu.com/p/e58ff90550df
博文:ElasticSearch 更改search线程池
https://kionf.com/2019/01/22/errornote-elk
博客园:探究ElasticSearch中的线程池实现
https://www.cnblogs.com/hapjin/p/10188056.html
CSDN:Elasticsearch线程池介绍
https://blog.csdn.net/opensure/article/details/51491815
官方:ElasticSearch线程池
https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-stats.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html
https://www.elastic.co/guide/en/elasticsearch/guide/current/_don_8217_t_touch_these_settings.html#_threadpools