ES_线程池_分析
本文将介绍 ES 的线程池和请求等待队列等知识。
施工中
线程池 参数介绍
_cat/thread_poolAPI 返回了线程池的相关信息,其中 active 表示活跃的线程数量,queue 表示正在等待中的任务数量,queue_size则表示当前 queue 的 size了。当队列中等待的任务超过了 queue_size时,请求将会被拒绝。
获取线程池配置
1  | // 两种 API 都可以查询线程池的状态  | 
| Field Name | Alias | Description | 
|---|---|---|
type | 
t | 
The current (*) type of thread pool (fixed or scaling) | 
active | 
a | 
The number of active threads in the current thread pool | 
size | 
s | 
The number of threads in the current thread pool | 
queue | 
q | 
The number of tasks in the queue for the current thread pool | 
queue_size | 
qs | 
The maximum number of tasks permitted in the queue for the current thread pool | 
rejected | 
r | 
The number of tasks rejected by the thread pool executor | 
largest | 
l | 
The highest number of active threads in the current thread pool | 
completed | 
c | 
The number of tasks completed by the thread pool executor | 
min | 
mi | 
The configured minimum number of active threads allowed in the current thread pool | 
max | 
ma | 
The configured maximum number of active threads allowed in the current thread pool | 
keep_alive | 
k | 
The configured keep alive time for threads | 
线程池类型
对于不同的功能,节点内部有不同的线程池来处理,区分线程池可以使节点更好的管理线程内存的消费。
许多线程池都由对应的队列,用于存储 Pending 请求而不是丢弃。
以下是各个请求的功能,按需查看。
genericFor generic operations (for example, background node discovery). Thread pool type is
scaling.searchFor count/search/suggest operations. Thread pool type is
fixed_auto_queue_sizewith a size ofint((# of available_processors * 3) / 2) + 1, and initial queue_size of1000.search_throttledFor count/search/suggest/get operations on
search_throttled indices. Thread pool type isfixed_auto_queue_sizewith a size of1, and initial queue_size of100.getFor get operations. Thread pool type is
fixedwith a size of# of available processors, queue_size of1000.analyzeFor analyze requests. Thread pool type is
fixedwith a size of1, queue size of16.writeFor single-document index/delete/update and bulk requests. Thread pool type is
fixedwith a size of# of available processors, queue_size of200. The maximum size for this pool is1 + # of available processors.snapshotFor snapshot/restore operations. Thread pool type is
scalingwith a keep-alive of5mand a max ofmin(5, (# of available processors)/2).warmerFor segment warm-up operations. Thread pool type is
scalingwith a keep-alive of5mand a max ofmin(5, (# of available processors)/2).refreshFor refresh operations. Thread pool type is
scalingwith a keep-alive of5mand a max ofmin(10, (# of available processors)/2).listenerMainly for java client executing of action when listener threaded is set to
true. Thread pool type isscalingwith a default max ofmin(10, (# of available processors)/2).fetch_shard_startedFor listing shard states. Thread pool type is
scalingwith keep-alive of5mand a default maximum size of2 * # of available processors.fetch_shard_storeFor listing shard stores. Thread pool type is
scalingwith keep-alive of5mand a default maximum size of2 * # of available processors.flushFor flush, synced flush, and translog
fsyncoperations. Thread pool type isscalingwith a keep-alive of5mand a default maximum size ofmin(5, (# of available processors)/2).force_mergeFor force merge operations. Thread pool type is
fixedwith a size of 1 and an unbounded queue size.managementFor cluster management. Thread pool type is
scalingwith a keep-alive of5mand a default maximum size of5.
线程池的参数
线程池有三种不同的模式,分别为 fixed, scaling, fixed-auto-queue-size,对于不同的类型的线程池,配置参数也不相同。
fixed
1  | thread_pool:  | 
scaling
scaling类型的线程池持有动态数量的线程。线程数量随集群负载 和 core & max的值成比例变化。
keep_alive参数决定一个线程空闲多久会被移除。
1  | thread_pool:  | 
实验性功能,请根据具体版本,查看对应官方文档。
处理器核数设置
处理器核数是自动感知的,线程池设置也是基于此自动设置的,可以通过以下的配置来修改该值,如果你确定你的场景需要修改这个值。
NOTE: 这是个专家级的配置,会牵涉到许多不同的配置,比如说改变 GC 线程的数量,pinning processes to cores等等。
1  | processors: 2  | 
此处介绍几个需要覆盖processors值的场景:
- 当我们需要 ES只使用一部分处理器性能时,比如一台机器上运行了2个 ES 实例,我们会希望每个实例只使用一半的 CPU 资源,就可以手动修改处理器核数。
 - 当ES 错误的检测了节点的 CPU 核数时,这个值可以通过 GET /_nodes,查看 OS 对象的值来获取。
 
是否需要变更线程池的大小
Elasticsearch 默认的线程设置已经是很合理。
对于所有的线程池(除了 search ),线程个数是根据 CPU 核心数设置的。 如果你有 8 个核,你可以同时运行的只有 8 个线程,只分配 8 个线程给任何特定的线程池是有道理的。
Search线程池设置的大一点,配置为 int(( 核心数 * 3 )/ 2 )+ 1 。
你可能会认为某些线程可能会阻塞(如磁盘上的 I/O 操作),所以你才想加大线程的。对于 Elasticsearch 来说这并不是一个问题:因为大多数 I/O 的操作是由 Lucene 线程管理的,而不是 Elasticsearch。
此外,线程池通过传递彼此之间的工作配合。你不必再因为它正在等待磁盘写操作而担心网络线程阻塞, 因为网络线程早已把这个工作交给另外的线程池,并且网络进行了响应。
最后,你的处理器的计算能力是有限的,拥有更多的线程会导致你的处理器频繁切换线程上下文。 一个处理器同时只能运行一个线程。所以当它需要切换到其它不同的线程的时候,它会存储当前的状态(寄存器等等),然后加载另外一个线程。 如果幸运的话,这个切换发生在同一个核心,如果不幸的话,这个切换可能发生在不同的核心,这就需要在内核间总线上进行传输。
这个上下文的切换,会给 CPU 时钟周期带来管理调度的开销;在现代的 CPUs 上,开销估计高达 30 μs。也就是说线程会被堵塞超过 30 μs,如果这个时间用于线程的运行,极有可能早就结束了。
所以,下次请不要调整线程池的线程数。如果你真 想调整 , 一定要关注你的 CPU 核心数,最多设置成核心数的两倍,再多了都是浪费。
修改 Therad Pool Queue Size
当同时接收过多请求,队列等待请求数量大于 queue_size 时,额外的请求就会被拒绝。
单纯的增加线程数量,对于提高系统的性能,作用有限,参考是否需要变更线程池的大小
直接增加等待队列的大小是相对可取的方案。
1  | thread_pool.search.queue_size: 500  | 
示例场景
通过代码生成大量写请求,来测试请求过载的场景。
目前设置 write 线程数量为1,发送1W 个请求,还是没有监测到 queue队列的拥堵现象。
考虑多线程发送请求,提高压力。
//todo