Elasticsearch 線程池和隊列問題,請先看這一篇
1、線程池相關線上實戰(zhàn)問題
問題1:從Kafka消費數(shù)據(jù)導入 elasticsearch 時,批量 bulk 寫入拋異常被拒絕。ES 集群四個節(jié)點,其中:兩個節(jié)點node1和node4 thread pool bulk rejected 30多萬條數(shù)據(jù),es bulk thread pool 線程數(shù)8、隊列200, Kafka寫線程池 thread數(shù)2*cores+cores/2、隊列數(shù)3。目前是想平衡一下寫的速度和 es 處理的速度,不過現(xiàn)在還沒有可用環(huán)境壓測,想問有經(jīng)驗數(shù)據(jù)或方法參考嗎?
問題2:多套系統(tǒng)使用一套集群,錯誤日志如下
{"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 初步解決方案:修改默認值、擴大隊列,根據(jù)業(yè)務后續(xù)持續(xù)觀察隊列大小,不再出現(xiàn)上述情形。
問題 1、2 都會引出:Elasticsearch 線程池和隊列知識點。
2、線程池概覽
Elasticsearch 使用線程池(Thread pool )來管理請求并優(yōu)化集群中每個節(jié)點上的資源使用。
3、線程池用途
主要線程池包括:搜索(search)、獲?。╣et)和寫入(write)等。
通過運行以下命令可以看到線程池全貌:
GET /_cat/GET /_cat/thread_pool/?v&h=id,name,active,rejected,completed,size,type&pretty&s=type

其中:
name:代表某一種線程池(寫入、檢索、刷新或其他)。
type:代表線程數(shù)類型。
通過運行上面的命令可以看到每個節(jié)點都有許多不同的線程池、線程池的大小和類型,還可以看到哪些節(jié)點拒絕了操作。
Elasticsearch根據(jù)每個節(jié)點中檢測到的線程數(shù)(number of processors,后面會講到這個參數(shù))自動配置線程池參數(shù)。
4、線程池類型
4.1 Fixed 類型
固定數(shù)量的線程,具有固定的隊列大小。
Fixed 類型線程使用示例如下:
thread_pool:
write:
size: 30
queue_size: 1000
4.2 Scaling 類型
可變數(shù)量的線程,Elasticsearch會根據(jù)工作負載自動調(diào)節(jié)線程大?。ㄖ到橛冢篶ore 到 max 之間)。
Scaling 類型線程使用示例如下:
thread_pool:
warmer:
core: 1
max: 8
4.3 fixed_autoqueue_size 線程
固定數(shù)量的線程,隊列大小會動態(tài)變化以保持目標響應時間。
該功能 8.0+ 版本會廢棄,這里也不著重講解。
fixed_autoqueue_size 類型線程使用示例如下:
強調(diào)了隊列大小可變。
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
值得注意的是,線程池是根據(jù) Elasticsearch 在基礎硬件上檢測到的線程數(shù)(number of processors)設置的。
如果檢測失敗,則應在 elasticsearch.yml 中顯式設置硬件中可用的線程數(shù)。
特別是在一臺宿主機配置多個 Elasticsearch 節(jié)點實例的情況下,若要修改其中一個節(jié)點線程池或隊列大小,則要考慮配置 processors 參數(shù)。
elasticsearch.yml 中設置如下所示:
processors: 4
PS:Linux 查看線程數(shù)方法:
grep 'processor' /proc/cpuinfo | sort -u | wc -l
認知 2:線程池關聯(lián)隊列設置
大多數(shù)線程池還具有與之關聯(lián)的隊列,以使 Elasticsearch 可以將請求存儲在內(nèi)存中,同時等待資源變得可用來處理請求。
但是,隊列通常具有有限的大小,如果超過該大小,Elasticsearch將拒絕該請求。
認知 3:很糟糕做法——盲目修改隊列大小
有時你可能會增加隊列的大小以防止請求被拒絕,但要結(jié)合資源實際進行修改,千萬別盲目修改。
實際上,如果值設置的非常大,甚至可能適得其反。因為通過設置更大的隊列大小,該節(jié)點將需要使用更多的內(nèi)存來存儲隊列,這就意味著將剩下相對較少的內(nèi)存來響應和管理實際請求。
此外,增加隊列大小還會增加將操作響應保留在隊列中的時間長度,從而導致客戶端應用程序面臨超時問題。
以下的莽撞行為,大家是要實戰(zhàn)中避免的。

認知 4:加強監(jiān)控
通常,唯一有需要增加隊列大小的情況是:在請求數(shù)量激增導致無法在客戶端管理此過程且資源使用率并未達到峰值。
你可以借助 Kibana Stack Monitoring 可視化監(jiān)控指標以更好地了解 Elasticsearch 集群的性能。
Kibana 監(jiān)控面板中的總視圖、節(jié)點視圖、索引視圖如下所示:
總視圖監(jiān)控

節(jié)點視圖監(jiān)控


索引視圖監(jiān)控

上圖是:Kibana 7.6 版本中的監(jiān)控截圖,標紅的地方是我在批量寫入數(shù)據(jù)。
search Rate:檢索速率
search Latency:檢索延時
indexing Rate:寫入速度
indexing Latency:寫入延時
隊列的增加(Growing)表明 Elasticsearch難以滿足請求,而拒絕(rejection)則表明隊列已經(jīng)增長到 Elasticsearch 拒絕的程度。
需要檢查導致隊列增加的根本原因,并嘗試通過在客戶端減輕相關寫入或檢索操作來平衡對集群線程池的壓力。
7、線程池線上實戰(zhàn)問題及注意事項
7.1 線程池和隊列修改需要更改配置文件 elasticsearch.yml
節(jié)點級別配置,而不再支持 5.X 之前的版本動態(tài) setting 修改。
重啟集群后生效。
7.2 reject 拒絕請求的原因有多種
類似文章開頭問題 2,如果 Elasticsearch 集群開始拒絕索引/寫入(index)請求,則可能有多種原因。
通常,這表明一個或多個節(jié)點無法跟上索引 / 刪除 / 更新 / 批量請求的數(shù)量,從而導致在該節(jié)點上建立隊列且隊列逐漸累積。
一旦索引隊列超過隊列的設置的最大值(如 elasticsearch.yml 定義的值或者默認值),則該節(jié)點將開始拒絕索引請求。
排查方法:需要檢查線程池的狀態(tài),以查明索引拒絕是否總是在同一節(jié)點上發(fā)生,還是分布在所有節(jié)點上。
GET /_cat/thread_pool?v
如果 reject 僅發(fā)生在特定的數(shù)據(jù)節(jié)點上,那么您可能會遇到負載平衡或分片問題。
如果 reject 與高 CPU 利用率相關聯(lián),那么通常這是 JVM 垃圾回收的結(jié)果,而 JVM 垃圾回收又是由配置或查詢相關問題引起的。
如果集群上有大量分片,則可能存在過度分片的問題。
如果觀察到節(jié)點上的隊列拒絕,但監(jiān)控發(fā)現(xiàn) CPU 未達到飽和,則磁盤寫入速度可能存在問題。
7.3 寫入 bulk 值要遞進步長調(diào)優(yōu)
不要妄圖快速提高寫入速度,一下調(diào)很大,很大勢必會寫入 reject。
首先嘗試一次索引 100 個文檔,然后索引 200 個,再索引 400 個,依此類推......
當索引寫入速度(indexing rate)開始趨于平穩(wěn)時,便知道已達到數(shù)據(jù)批量請求的最佳大小。
8、小結(jié)
寫入 reject、“429 too many requests” 等都是非常常見的錯誤,問題多半和線程池和隊列大小有關系,需要結(jié)合業(yè)務場景進行問題排查。
本文“拋磚引玉”,給出線程池和隊列相關總結(jié)知識。您在實戰(zhàn)中遇到的類似問題嗎?歡迎留言探討交流。
參考
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/
推薦:
中國最大的 Elastic 非官方公眾號
點擊查看“閱讀原文”,獲取近10小時進階視頻教程,和全球近 1000 位 Elastic 愛好者(含中國 50%+ Elastic 認證工程師)一起每日精進 ELK 技能!
