Elasticsearch 线程池和队列问题,请先看这一篇

简介: 1、线程池相关线上实战问题问题1:从Kafka消费数据导入 elasticsearch 时,批量 bulk 写入抛异常被拒绝。ES 集群四个节点,其中:两个节点node1和node4 thread pool bulk rejected 30多万条数据,es bulk thread pool 线程数8、队列200, Kafka写线程池 thread数2*cores+cores/2、队列数3。目前是想平衡一下写的速度和 es 处理的速度,不过现在还没有可用环境压测,想问有经验数据或方法参考吗?

image.png

链接

问题2:多套系统使用一套集群,错误日志如下


{"message": "failed to execute pipeline for a bulk request" ,

"stacktrace": ["org.elasticsearch.common.util.concurrent.EsRejectedExecutionException: rejected execution of org.elasticsearch.ingest.IngestService$4@5b522103 on EsThreadPoolExecutor[name = node-2/write, queue capacity = 1024, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@19bdbd79[Running, pool size = 5, active threads = 5, queued tasks = 1677, ]]",

针对问题 2,初步排查日志,是大量日志写入造成队列满了,造成集群直接拒绝写入了。


问题 2 初步解决方案:修改默认值、扩大队列,根据业务后续持续观察队列大小,不再出现上述情形。


问题 1、2 都会引出:Elasticsearch 线程池和队列知识点。


2、线程池概览

Elasticsearch 使用线程池(Thread pool )来管理请求并优化集群中每个节点上的资源使用。


3、线程池用途

主要线程池包括:搜索(search)、获取(get)和写入(write)等。


通过运行以下命令可以看到线程池全貌:


GET /_cat/GET /_cat/thread_pool/?v&h=id,name,active,rejected,completed,size,type&pretty&s=type

image.png

其中:


name:代表某一种线程池(写入、检索、刷新或其他)。


type:代表线程数类型。


通过运行上面的命令可以看到每个节点都有许多不同的线程池、线程池的大小和类型,还可以看到哪些节点拒绝了操作。


Elasticsearch根据每个节点中检测到的线程数(number of processors,后面会讲到这个参数)自动配置线程池参数。


4、线程池类型

4.1 Fixed 类型

固定数量的线程,具有固定的队列大小。


Fixed 类型线程使用示例如下:


thread_pool:

   write:

       size: 30

       queue_size: 1000

4.2 Scaling 类型

可变数量的线程,Elasticsearch会根据工作负载自动调节线程大小(值介于:core 到 max 之间)。


Scaling 类型线程使用示例如下:


thread_pool:

   warmer:

       core: 1

       max: 8

4.3 fixed_autoqueue_size 线程

固定数量的线程,队列大小会动态变化以保持目标响应时间。


该功能 8.0+ 版本会废弃,这里也不着重讲解。


fixed_autoqueue_size 类型线程使用示例如下:


强调了队列大小可变。


thread_pool:

   search:

       size: 30

       queue_size: 500

       min_queue_size: 10

       max_queue_size: 1000

       auto_queue_frame_size: 2000

       target_response_time: 1s

5、线程池使用举例

若要查看哪些线程 CPU 利用率高或花费的时间最长,可以使用以下查询。


GET /_nodes/hot_threads

该 API 有助于排查性能问题。


更多推荐:深入解读 Elasticsearch 热点线程 hot_threads


6、线程池和队列认知

认知 1:必要时设置:processors

值得注意的是,线程池是根据 Elasticsearch 在基础硬件上检测到的线程数(number of processors)设置的。


如果检测失败,则应在 elasticsearch.yml 中显式设置硬件中可用的线程数。


特别是在一台宿主机配置多个 Elasticsearch 节点实例的情况下,若要修改其中一个节点线程池或队列大小,则要考虑配置 processors 参数。


elasticsearch.yml 中设置如下所示:


processors: 4

PS:Linux 查看线程数方法:


grep 'processor' /proc/cpuinfo | sort -u | wc -l

认知 2:线程池关联队列设置

大多数线程池还具有与之关联的队列,以使 Elasticsearch 可以将请求存储在内存中,同时等待资源变得可用来处理请求。


但是,队列通常具有有限的大小,如果超过该大小,Elasticsearch将拒绝该请求。


认知 3:很糟糕做法——盲目修改队列大小

有时你可能会增加队列的大小以防止请求被拒绝,但要结合资源实际进行修改,千万别盲目修改。


实际上,如果值设置的非常大,甚至可能适得其反。因为通过设置更大的队列大小,该节点将需要使用更多的内存来存储队列,这就意味着将剩下相对较少的内存来响应和管理实际请求。


此外,增加队列大小还会增加将操作响应保留在队列中的时间长度,从而导致客户端应用程序面临超时问题。


以下的莽撞行为,大家是要实战中避免的。

认知 4:加强监控

通常,唯一有需要增加队列大小的情况是:在请求数量激增导致无法在客户端管理此过程且资源使用率并未达到峰值。


你可以借助 Kibana Stack Monitoring 可视化监控指标以更好地了解 Elasticsearch 集群的性能。


Kibana 监控面板中的总视图、节点视图、索引视图如下所示:


总视图监控

image.png

  • 节点视图监控

image.png

image.png

  • 索引视图监控

image.png

上图是:Kibana 7.6 版本中的监控截图,标红的地方是我在批量写入数据。


search Rate:检索速率


search Latency:检索延时


indexing Rate:写入速度


indexing Latency:写入延时


队列的增加(Growing)表明 Elasticsearch难以满足请求,而拒绝(rejection)则表明队列已经增长到 Elasticsearch 拒绝的程度。


需要检查导致队列增加的根本原因,并尝试通过在客户端减轻相关写入或检索操作来平衡对集群线程池的压力。


7、线程池线上实战问题及注意事项

7.1 线程池和队列修改需要更改配置文件 elasticsearch.yml

节点级别配置,而不再支持 5.X 之前的版本动态 setting 修改。


重启集群后生效。


7.2 reject 拒绝请求的原因有多种

类似文章开头问题 2,如果 Elasticsearch 集群开始拒绝索引/写入(index)请求,则可能有多种原因。


通常,这表明一个或多个节点无法跟上索引 / 删除 / 更新 / 批量请求的数量,从而导致在该节点上建立队列且队列逐渐累积。


一旦索引队列超过队列的设置的最大值(如 elasticsearch.yml 定义的值或者默认值),则该节点将开始拒绝索引请求。


排查方法:需要检查线程池的状态,以查明索引拒绝是否总是在同一节点上发生,还是分布在所有节点上。


GET /_cat/thread_pool?v

如果 reject 仅发生在特定的数据节点上,那么您可能会遇到负载平衡或分片问题。


如果 reject 与高 CPU 利用率相关联,那么通常这是 JVM 垃圾回收的结果,而 JVM 垃圾回收又是由配置或查询相关问题引起的。


如果集群上有大量分片,则可能存在过度分片的问题。


如果观察到节点上的队列拒绝,但监控发现 CPU 未达到饱和,则磁盘写入速度可能存在问题。


7.3 写入 bulk 值要递进步长调优

不要妄图快速提高写入速度,一下调很大,很大势必会写入 reject。


首先尝试一次索引 100 个文档,然后索引 200 个,再索引 400 个,依此类推......


当索引写入速度(indexing rate)开始趋于平稳时,便知道已达到数据批量请求的最佳大小。


8、小结

写入 reject、“429  too many requests” 等都是非常常见的错误,问题多半和线程池和队列大小有关系,需要结合业务场景进行问题排查。


本文“抛砖引玉”,给出线程池和队列相关总结知识。您在实战中遇到的类似问题吗?欢迎留言探讨交流。


参考

https://drscg.tistory.com/640


https://opster.com/elasticsearch-glossary/index-queue-size-is-high/


https://opster.com/elasticsearch-glossary/elasticsearch-threadpool/


https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html


https://opster.com/analysis/elasticsearch-requested-thread-pool-size-for-is-too-large-setting-to-maximum-instead/


推荐:


全网首发!《 Elasticsearch 最少必要知识教程 V1.0 》低调发布


从实战中来,到实战中去——Elasticsearch 技能更快提升方法论


Elasticsearch写入原理深入详解


Elasticsearch性能优化实战指南


让Elasticsearch飞起来!——性能优化实践干货

相关实践学习
以电商场景为例搭建AI语义搜索应用
本实验旨在通过阿里云Elasticsearch结合阿里云搜索开发工作台AI模型服务,构建一个高效、精准的语义搜索系统,模拟电商场景,深入理解AI搜索技术原理并掌握其实现过程。
ElasticSearch 最新快速入门教程
本课程由千锋教育提供。全文搜索的需求非常大。而开源的解决办法Elasricsearch(Elastic)就是一个非常好的工具。目前是全文搜索引擎的首选。本系列教程由浅入深讲解了在CentOS7系统下如何搭建ElasticSearch,如何使用Kibana实现各种方式的搜索并详细分析了搜索的原理,最后讲解了在Java应用中如何集成ElasticSearch并实现搜索。  
相关文章
|
安全
python_threading多线程、queue安全队列
python_threading多线程、queue安全队列
295 2
|
存储 监控 Java
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
925 12
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
1136 7
|
消息中间件 存储 安全
|
安全 Java 容器
【JaveEE】——多线程中使用顺序表,队列,哈希表
多线程环境下使用ArrayList(同步机制,写时拷贝),使用队列,哈希表(高频)ConcurrentHashMap(缩小锁粒度,CAS,扩容优化)
|
存储 运维 API
源码解密协程队列和线程队列的实现原理(一)
源码解密协程队列和线程队列的实现原理(一)
436 1
|
存储 安全 API
源码解密协程队列和线程队列的实现原理(二)
源码解密协程队列和线程队列的实现原理(二)
191 1
|
存储 监控 Java
|
设计模式 安全 Java
Java面试题:请解释Java中的线程池以及为什么要使用线程池?请解释Java中的内存模型以及如何避免内存泄漏?请解释Java中的并发工具包以及如何实现一个简单的线程安全队列?
Java面试题:请解释Java中的线程池以及为什么要使用线程池?请解释Java中的内存模型以及如何避免内存泄漏?请解释Java中的并发工具包以及如何实现一个简单的线程安全队列?
252 1

热门文章

最新文章