歸並線程配置
segment 歸並的過程,需要先讀取 segment,歸並計算,再寫一遍 segment,最后還要保證刷到磁盤。可以說,這是一個非常消耗磁盤 IO 和 CPU 的任務。所以,ES 提供了對歸並線程的限速機制,確保這個任務不會過分影響到其他任務。
在 5.0 之前,歸並線程的限速配置 indices.store.throttle.max_bytes_per_sec
是 20MB。對於寫入量較大,磁盤轉速較高,甚至使用 SSD 盤的服務器來說,這個限速是明顯過低的。對於 Elastic Stack 應用,社區廣泛的建議是可以適當調大到 100MB或者更高。
# curl -XPUT http://127.0.0.1:9200/_cluster/settings -d'
{
"persistent" : {
"indices.store.throttle.max_bytes_per_sec" : "100mb"
}
}'
5.0 開始,ES 對此作了大幅度改進,使用了 Lucene 的 CMS(ConcurrentMergeScheduler) 的 auto throttle 機制,正常情況下已經不再需要手動配置 indices.store.throttle.max_bytes_per_sec
了。官方文檔中都已經刪除了相關介紹,不過從源碼中還是可以看到,這個值目前的默認設置是 10240 MB。
歸並線程的數目,ES 也是有所控制的。默認數目的計算公式是: Math.min(3, Runtime.getRuntime().availableProcessors() / 2)
。即服務器 CPU 核數的一半大於 3 時,啟動 3 個歸並線程;否則啟動跟 CPU 核數的一半相等的線程數。相信一般做 Elastic Stack 的服務器 CPU 合數都會在 6 個以上。所以一般來說就是 3 個歸並線程。如果你確定自己磁盤性能跟不上,可以降低index.merge.scheduler.max_thread_count
配置,免得 IO 情況更加惡化。
歸並策略
歸並線程是按照一定的運行策略來挑選 segment 進行歸並的。主要有以下幾條:
- index.merge.policy.floor_segment 默認 2MB,小於這個大小的 segment,優先被歸並。
- index.merge.policy.max_merge_at_once 默認一次最多歸並 10 個 segment
- index.merge.policy.max_merge_at_once_explicit 默認 forcemerge 時一次最多歸並 30 個 segment。
- index.merge.policy.max_merged_segment 默認 5 GB,大於這個大小的 segment,不用參與歸並。forcemerge 除外。
根據這段策略,其實我們也可以從另一個角度考慮如何減少 segment 歸並的消耗以及提高響應的辦法:加大 flush 間隔,盡量讓每次新生成的 segment 本身大小就比較大。
forcemerge 接口
既然默認的最大 segment 大小是 5GB。那么一個比較龐大的數據索引,就必然會有為數不少的 segment 永遠存在,這對文件句柄,內存等資源都是極大的浪費。但是由於歸並任務太消耗資源,所以一般不太選擇加大 index.merge.policy.max_merged_segment
配置,而是在負載較低的時間段,通過 forcemerge 接口,強制歸並 segment。
# curl -XPOST http://127.0.0.1:9200/logstash-2015-06.10/_forcemerge?max_num_segments=1
由於 forcemerge 線程對資源的消耗比普通的歸並線程大得多,所以,絕對不建議對還在寫入數據的熱索引執行這個操作。這個問題對於 Elastic Stack 來說非常好辦,一般索引都是按天分割的。更合適的任務定義方式,請閱讀本書稍后的 curator 章節。