ElasticSearch优化之线程池介绍
# 提升性能:Elasticsearch 线程池的详细介绍
Elasticsearch使用多个线程池(thread pool)来管理内存消耗和处理并发请求。这些线程池负责不同类型的任务,通过线程和队列的配置来平衡系统的资源使用和性能。在队列中,挂起的请求可以暂时被保存而不是直接丢弃,从而减少因系统资源不足而导致的请求失败。
文章详细介绍了各类线程池的配置方法及其对应的场景,通过优化线程池,特别是在高并发环境下,能够减少请求失败,提升整体系统的稳定性和响应速度。
# 1. 线程池概述
线程池是Elasticsearch中用于处理不同类型任务的核心机制。每个节点都有多个线程池,负责处理不同类型的操作。这些线程池的类型和配置可以显著影响Elasticsearch集群的性能和资源使用。
# 主要线程池概述
- Generic 线程池:用于处理通用的后台任务,如节点发现等操作,具备动态扩展能力。
- Index 线程池:负责文档的索引和删除操作,配置固定数量的线程。
- Search 线程池:专门处理搜索、计数和建议操作,确保高效的搜索性能。
- Get 线程池:用于处理单个文档的获取请求,处理高频查询操作。
- Bulk 线程池:处理批量索引、更新和删除请求,优化批量操作的并发处理。
- Snapshot 线程池:用于创建和恢复快照操作,具备动态调整线程数的能力。
- Warmer 线程池:负责分段预热操作,确保新分段在被查询前已准备就绪。
- Refresh 线程池:执行索引刷新操作,将新数据从内存持久化到磁盘。
- Listener 线程池:用于 Java 客户端异步操作监听,确保监听操作独立于主线程池执行。
# 1.1 线程池的作用
Elasticsearch中的每个线程池都有其特定的用途,例如:
- Generic 线程池负责后台操作,例如节点发现、定时任务。
- Search 线程池主要用于搜索、建议等操作。
- Write 线程池用于处理索引、删除、更新文档等操作。
合理配置这些线程池能够有效管理系统资源并优化性能。
# 2. 线程池的详细介绍
Elasticsearch中的线程池在处理并发操作、优化资源使用和提高性能方面起着至关重要的作用。下面将详细介绍 generic
、index
、search
、get
、bulk
、snapshot
、warmer
、refresh
和 listener
这些常见线程池的用途和配置。
说明: ${node.processors}
为 node.processors: 2
设置的值。
系统会自动检测处理器的数量,并基于它自动设置线程池设置。在某些情况下,覆盖检测到的处理器数量可能很有用。这可以通过显式设置 node.processors 设置来完成。
# 查看配置方法
GET _nodes/thread_pool
# generic线程池
- 用途:用于通用操作,如后台节点发现、一些周期性任务等。
- 线程池类型:
scaling
- 说明:线程数可以根据需求动态扩展。
# 配置方法
在elasticsearch.yml
配置文件中添加以下内容:
thread_pool.generic.type: scaling
thread_pool.generic.core: 4
thread_pool.generic.max: 128
thread_pool.generic.keep_alive: 30s
2
3
4
# search线程池
- 用途:用于处理搜索、计数、推荐等操作。
- 线程池类型:
fixed_auto_queue_size
- 大小:
int((${node.processors} * 3) / 2) + 1
- 初始队列大小:1000
- 说明:该线程池的大小默认是根据系统处理器的数量自动计算的。
# 配置方法
thread_pool.search.type: fixed_auto_queue_size
thread_pool.search.size: 13
thread_pool.search.queue_size: 1000
2
3
# search_throttled线程池
- 用途:用于处理搜索受限索引上的操作,如
count/search/suggest/get
。 - 线程池类型:
fixed_auto_queue_size
- 大小:1
- 初始队列大小:100
- 说明:由于受限索引通常不会有大量的并发操作,因此此线程池配置为单线程。
# 配置方法
thread_pool.search_throttled.type: fixed_auto_queue_size
thread_pool.search_throttled.size: 1
thread_pool.search_throttled.queue_size: 100
2
3
# get线程池
- 用途:处理获取文档的操作。
- 线程池类型:
fixed
- 大小:等于分配的处理器数。
- 队列大小:1000
- 说明:此线程池用于检索单个文档的操作。
# 配置方法
thread_pool.get.type: fixed
thread_pool.get.size: 8
thread_pool.get.queue_size: 1000
2
3
# analyze线程池
- 用途:用于分析请求,如文本分词和分析操作。
- 线程池类型:
fixed
- 大小:1
- 队列大小:16
- 说明:分析操作通常是短期操作,因此此线程池的配置较小。
# 配置方法
thread_pool.analyze.type: fixed
thread_pool.analyze.size: 1
thread_pool.analyze.queue_size: 16
2
3
# write线程池
- 用途:用于处理单文档索引、删除、更新以及批量请求。
- 线程池类型:
fixed
- 大小:等于分配的处理器数。
- 队列大小:10000
- 说明:此线程池负责所有与写入相关的操作,队列较大,以处理潜在的大量写入请求。
# 配置方法
thread_pool.write.type: fixed
thread_pool.write.size: 8
thread_pool.write.queue_size: 10000
2
3
# snapshot线程池
- 用途:用于快照和恢复操作。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:
min(5, (${node.processors}) / 2)
- 说明:快照和恢复操作通常是后台操作,因此使用扩展线程池来根据负载动态调整。
# 配置方法
thread_pool.snapshot.type: scaling
thread_pool.snapshot.keep_alive: 5m
thread_pool.snapshot.max: 4
2
3
# snapshot_meta线程池
- 用途:用于快照库元数据的读取操作。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:
min(50, (${node.processors} * 3))
# 配置方法
thread_pool.snapshot_meta.type: scaling
thread_pool.snapshot_meta.keep_alive: 5m
thread_pool.snapshot_meta.max: 50
2
3
# warmer线程池
- 用途:用于段预热操作。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:
min(5, (${node.processors}) / 2)
- 说明:当新段写入时,Elasticsearch通过预热操作优化性能。
# 配置方法
thread_pool.warmer.type: scaling
thread_pool.warmer.keep_alive: 5m
thread_pool.warmer.max: 4
2
3
# refresh线程池
- 用途:用于刷新操作,确保数据能够及时搜索到。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:
min(10, (${node.processors}) / 2)
- 说明:刷新操作可以在后台执行,并随着负载的变化进行扩展。
# 配置方法
thread_pool.refresh.type: scaling
thread_pool.refresh.keep_alive: 5m
thread_pool.refresh.max: 6
2
3
# listener线程池
- 用途:主要用于Java客户端在监听器设置为
true
时执行操作。 - 线程池类型:
scaling
- 最大线程池大小:
min(10, (${node.processors}) / 2)
- 说明:此线程池处理来自客户端的操作监听,确保操作结果能够及时返回给客户端。
# 配置方法
thread_pool.listener.type: scaling
thread_pool.listener.max: 6
2
# fetch_shard_started线程池
- 用途:用于列出分片状态。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:2 * 分配的处理器数。
- 说明:用于处理分片恢复过程中列出分片状态的操作。
# 配置方法
thread_pool.fetch_shard_started.type: scaling
thread_pool.fetch
_shard_started.keep_alive: 5m
thread_pool.fetch_shard_started.max: 16
2
3
4
5
# fetch_shard_store线程池
- 用途:用于处理分片存储列表操作。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:2 * 分配的处理器数。
- 说明:处理从分片存储中获取数据的操作。
# 配置方法
thread_pool.fetch_shard_store.type: scaling
thread_pool.fetch_shard_store.keep_alive: 5m
thread_pool.fetch_shard_store.max: 16
2
3
# flush线程池
- 用途:用于定期将内存中的数据写入磁盘。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:
min(10, (${node.processors}))
- 说明:定期刷新操作确保Elasticsearch的数据一致性与持久性。
# 配置方法
thread_pool.flush.type: scaling
thread_pool.flush.keep_alive: 5m
thread_pool.flush.max: 10
2
3
# force_merge线程池
- 用途:用于段合并操作。
- 线程池类型:
fixed
- 大小:1
- 队列大小:
Integer.MAX_VALUE
- 说明:段合并是资源密集型操作,因此强制合并操作被限制为单线程。
# 配置方法
thread_pool.force_merge.type: fixed
thread_pool.force_merge.size: 1
thread_pool.force_merge.queue_size: -1
2
3
# management线程池
- 用途:处理集群的后台管理任务,如集群状态更新。
- 线程池类型:
scaling
- 最大线程池大小:5
- 说明:用于处理集群管理任务,确保集群状态和任务分发的稳定性。
# 配置方法
thread_pool.management.type: scaling
thread_pool.management.max: 5
2
# system_read线程池
- 用途:用于处理系统级别的读取请求。
- 线程池类型:
fixed_auto_queue_size
- 大小:2
- 说明:专门为系统级别的读取操作优化,队列大小根据负载动态调整。
# 配置方法
thread_pool.system_read.type: fixed_auto_queue_size
thread_pool.system_read.size: 2
2
# system_write线程池
- 用途:用于处理系统级别的写入请求。
- 线程池类型:
fixed_auto_queue_size
- 大小:2
- 说明:类似
system_read
,专注于处理系统写入操作。
# 配置方法
thread_pool.system_write.type: fixed_auto_queue_size
thread_pool.system_write.size: 2
2
# system_critical_read线程池
- 用途:处理关键的系统级别读取操作。
- 线程池类型:
fixed_auto_queue_size
- 大小:1
- 说明:为关键系统操作设计,确保读取操作能在高负载情况下得到优先处理。
# 配置方法
thread_pool.system_critical_read.type: fixed_auto_queue_size
thread_pool.system_critical_read.size: 1
2
# system_critical_write线程池
- 用途:处理关键的系统级别写入操作。
- 线程池类型:
fixed_auto_queue_size
- 大小:1
- 说明:同样针对关键系统操作,确保写入操作的顺利进行。
# 配置方法
thread_pool.system_critical_write.type: fixed_auto_queue_size
thread_pool.system_critical_write.size: 1
2
# watcher线程池
- 用途:处理Watchers任务,通常用于监控任务。
- 线程池类型:
scaling
- 保活时间:5分钟
- 最大线程池大小:1
- 说明:Elasticsearch的监控和报警框架Watcher依赖此线程池进行触发和处理。
# 配置方法
thread_pool.watcher.type: scaling
thread_pool.watcher.keep_alive: 5m
thread_pool.watcher.max: 1
2
3
# 3. 线程池类型和参数配置方法
Elasticsearch支持不同类型的线程池,适用于不同场景和工作负载。
# 3.1 固定大小线程池(fixed)
固定大小线程池用于处理请求,线程池大小固定,且有一个(可选的)有界队列用于处理无法立即执行的挂起请求。
- size:控制线程池中的线程数量。
- queue_size:控制挂起请求队列的大小,默认为
-1
表示无界。当请求到达且队列已满时,系统会中止请求。
thread_pool:
write:
size: 30
queue_size: 1000
2
3
4
# 3.2 固定自动队列大小线程池(fixed_auto_queue_size)
该类型线程池类似于固定大小线程池,但挂起请求队列的大小会根据Little's Law的计算动态调整。随着处理的请求数量增加,队列大小可能会调整。
- size:线程池大小。
- queue_size:初始队列大小。
- min_queue_size:队列的最小大小。
- max_queue_size:队列的最大大小。
- auto_queue_frame_size:控制在调整队列之前需要完成的操作数量。
- target_response_time:目标响应时间,用于动态调整队列大小。
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
2
3
4
5
6
7
8
# 3.3 动态扩展线程池(scaling)
动态扩展线程池会根据工作负载动态调整线程数量。线程池的线程数量在core
(核心线程数)和max
(最大线程数)之间浮动。
- core:线程池的最小线程数。
- max:线程池的最大线程数。
- keep_alive:线程在无工作负载时保持活动的时间。
thread_pool:
warmer:
core: 1
max: 8
keep_alive: 2m
2
3
4
5
# 4. 分配处理器设置
线程池的大小通常是基于系统中分配的处理器数量决定的,合理配置处理器可以显著提升性能。
node.processors: 16
通过设置 node.processors
参数,用户可以限制分配给线程池的处理器数量。
# 5. 修改线程池配置
可以通过 elasticsearch.yml
文件或动态更新API来调整线程池的配置。例如,动态更新索引线程池的配置:
PUT /_cluster/settings
{
"persistent": {
"thread_pool.index.size": 40,
"thread_pool.index.queue_size": 500
}
}
2
3
4
5
6
7
# 6. 总结
Elasticsearch中的线程池机制极大地提高了系统的资源利用率和性能。通过合理配置各类线程池,用户能够根据自己的使用场景来优化集群的运行效率。在高并发环境下,优化线程池的配置尤其重要,能够有效地避免系统过载并减少请求失败的情况。
注:
本文档介绍版本为:7.14 ,其他版本可能会有所不同。具体可以参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.14/modules-threadpool.html