Elasticsearch 调优之 写入速度优化到极限
基于版本: 2.x – 5.x
在 es 的默認(rèn)設(shè)置,是綜合考慮數(shù)據(jù)可靠性,搜索實(shí)時(shí)性,寫(xiě)入速度等因素的,當(dāng)你離開(kāi)默認(rèn)設(shè)置,追求極致的寫(xiě)入速度時(shí),很多是以犧牲可靠性和搜索實(shí)時(shí)性為代價(jià)的.有時(shí)候,業(yè)務(wù)上對(duì)兩者要求并不高,反而對(duì)寫(xiě)入速度要求很高,例如在我的場(chǎng)景中,要求每秒200w 條的平均寫(xiě)入速度,每條500字節(jié)左右
接下來(lái)的優(yōu)化基于集群正常運(yùn)行的前提下,如果是集群首次灌入數(shù)據(jù),可以將副本數(shù)設(shè)置為0,寫(xiě)入完畢再調(diào)整回去,這樣副本分片只需要拷貝,節(jié)省了索引過(guò)程.
綜合來(lái)說(shuō),提升寫(xiě)入速度從以下幾方面入手:
加大 translog flush ,目的是降低 iops,writeblock
加大 index refresh間隔, 目的除了降低 io, 更重要的降低了 segment merge 頻率
調(diào)整 bulk 線(xiàn)程池和隊(duì)列
優(yōu)化磁盤(pán)間的任務(wù)均勻情況,將 shard 盡量均勻分布到物理主機(jī)的各磁盤(pán)
優(yōu)化節(jié)點(diǎn)間的任務(wù)分布,將任務(wù)盡量均勻的發(fā)到各節(jié)點(diǎn)
優(yōu)化 lucene 層建立索引的過(guò)程,目的是降低 CPU 占用率及 IO
translog flush 間隔調(diào)整
從 es 2.x 開(kāi)始, 默認(rèn)設(shè)置下,translog 的持久化策略為:每個(gè)請(qǐng)求都flush.對(duì)應(yīng)配置項(xiàng)為:
|
1 |
|
這是影響 es 寫(xiě)入速度的最大因素.但是只有這樣,寫(xiě)操作才有可能是可靠的,原因參考寫(xiě)入流程.
如果系統(tǒng)可以接受一定幾率的數(shù)據(jù)丟失,調(diào)整 translog 持久化策略為周期性和一定大小的時(shí)候 flush:
|
1 |
|
索引刷新間隔調(diào)整: refresh_interval
refresh_interval
默認(rèn)情況下索引的refresh_interval為1秒,這意味著數(shù)據(jù)寫(xiě)1秒后就可以被搜索到,每次索引的 refresh 會(huì)產(chǎn)生一個(gè)新的 lucene 段,這會(huì)導(dǎo)致頻繁的 segment merge 行為,如果你不需要這么高的搜索實(shí)時(shí)性,應(yīng)該降低索引refresh 周期,如:
|
1 |
|
segment merge
segment merge 操作對(duì)系統(tǒng) CPU 和 IO 占用都比較高,從es 2.0開(kāi)始,merge 行為不再由 es 控制,而是轉(zhuǎn)由 lucene 控制,因此以下配置已被刪除:
|
1 |
|
改為以下調(diào)整開(kāi)關(guān):
|
1 |
|
最大線(xiàn)程數(shù)的默認(rèn)值為:
|
1 |
|
是一個(gè)比較理想的值,如果你只有一塊硬盤(pán)并且非 SSD, 應(yīng)該把他設(shè)置為1,因?yàn)樵谛D(zhuǎn)存儲(chǔ)介質(zhì)上并發(fā)寫(xiě),由于尋址的原因,不會(huì)提升,只會(huì)降低寫(xiě)入速度.
merge 策略有三種:
tiered
log_byete_size
log_doc
默認(rèn)情況下:
|
1 |
|
索引創(chuàng)建時(shí)合并策略就已確定,不能更改,但是可以動(dòng)態(tài)更新策略參數(shù),一般情況下,不需要調(diào)整.如果堆棧經(jīng)常有很多 merge, 可以嘗試調(diào)整以下配置:
|
1 |
|
該屬性用于阻止segment 的頻繁flush, 小于此值將考慮優(yōu)先合并,默認(rèn)為2M,可考慮適當(dāng)降低此值
|
1 |
|
該屬性指定了每層分段的數(shù)量,取值約小最終segment 越少,因此需要 merge 的操作更多,可以考慮適當(dāng)增加此值.默認(rèn)為10,他應(yīng)該大于等于 index.merge.policy.max_merge_at_once
|
1 |
|
指定了單個(gè) segment 的最大容量,默認(rèn)為5GB,可以考慮適當(dāng)降低此值
Indexing Buffer
indexing buffer在為 doc 建立索引時(shí)使用,當(dāng)緩沖滿(mǎn)時(shí)會(huì)刷入磁盤(pán),生成一個(gè)新的 segment, 這是除refresh_interval外另外一個(gè)刷新索引,生成新 segment 的機(jī)會(huì). 每個(gè) shard 有自己的 indexing buffer,下面的關(guān)于這個(gè) buffer 大小的配置需要除以這個(gè)節(jié)點(diǎn)上所有的 shard 數(shù)量
|
1 |
|
默認(rèn)為整個(gè)堆空間的10%
|
1 |
|
默認(rèn)48mb
|
1 |
|
默認(rèn)無(wú)限制
在大量的索引操作時(shí),indices.memory.index_buffer_size默認(rèn)設(shè)置可能不夠,這和可用堆內(nèi)存,單節(jié)點(diǎn)上的 shard 數(shù)量相關(guān),可以考慮適當(dāng)增大.
bulk 線(xiàn)程池和隊(duì)列大小
建立索引的過(guò)程偏計(jì)算密集型任務(wù),應(yīng)該使用固定大小的線(xiàn)程池配置,來(lái)不及處理的放入隊(duì)列,線(xiàn)程數(shù)量配置為 CPU 核心數(shù)+1,避免過(guò)多的上下文切換.隊(duì)列大小可以適當(dāng)增加.
磁盤(pán)間的任務(wù)均衡
如果你的部署方案是為path.data 配置多個(gè)路徑來(lái)使用多塊磁盤(pán), es 在分配 shard 時(shí),落到各磁盤(pán)上的 shard 可能并不均勻,這種不均勻可能會(huì)導(dǎo)致某些磁盤(pán)繁忙,利用率達(dá)到100%,這種不均勻達(dá)到一定程度可能會(huì)對(duì)寫(xiě)入性能產(chǎn)生負(fù)面影響.
es 在處理多路徑時(shí),優(yōu)先將 shard 分配到可用空間百分比最多的磁盤(pán),因此短時(shí)間內(nèi)創(chuàng)建的 shard 可能被集中分配到這個(gè)磁盤(pán),即使可用空間是99%和98%的差別.后來(lái) es 在2.x 版本中開(kāi)始解決這個(gè)問(wèn)題的方式是:預(yù)估一下這個(gè) shard 會(huì)使用的空間,從磁盤(pán)可用空間中減去這部分,直到現(xiàn)在6.x beta 版也是這種處理方式.但是實(shí)現(xiàn)也存在一些問(wèn)題:
從可用空間減去預(yù)估大小
這種機(jī)制只存在于一次索引創(chuàng)建的過(guò)程中,下一次的索引創(chuàng)建,磁盤(pán)可用空間并不是上次做完減法以后的結(jié)果,這也可以理解,畢竟預(yù)估是不準(zhǔn)的,一直減下去很快就減沒(méi)了.
但是最終的效果是,這種機(jī)制并沒(méi)有從根本上解決問(wèn)題,即使沒(méi)有完美的解決方案,這種機(jī)制的效果也不夠好.
如果單一的機(jī)制不能解決所有的場(chǎng)景,至少應(yīng)該為不同場(chǎng)景準(zhǔn)備多種選擇.
為此,我們?yōu)?es 增加了兩種策略
簡(jiǎn)單輪詢(xún):系統(tǒng)初始階段,簡(jiǎn)單輪詢(xún)的效果是最均勻的
基于可用空間的動(dòng)態(tài)加權(quán)輪詢(xún):以可用空間作為權(quán)重,在磁盤(pán)之間加權(quán)輪詢(xún)
節(jié)點(diǎn)間的任務(wù)均衡
為了在節(jié)點(diǎn)間任務(wù)盡量均衡,數(shù)據(jù)寫(xiě)入客戶(hù)端應(yīng)該把 bulk 請(qǐng)求輪詢(xún)發(fā)送到各個(gè)節(jié)點(diǎn).
當(dāng)使用 java api ,或者 rest api 的 bulk 接口發(fā)送數(shù)據(jù)時(shí),客戶(hù)端將會(huì)輪詢(xún)的發(fā)送的集群節(jié)點(diǎn),節(jié)點(diǎn)列表取決于:
當(dāng)client.transport.sniff為 true,(默認(rèn)為 false),列表為所有數(shù)據(jù)節(jié)點(diǎn)
否則,列表為初始化客戶(hù)端對(duì)象時(shí)添加進(jìn)去的節(jié)點(diǎn).
java api 的 TransportClient 和 rest api 的 RestClient 都是線(xiàn)程安全的,當(dāng)寫(xiě)入程序自己創(chuàng)建線(xiàn)程池控制并發(fā),應(yīng)該使用同一個(gè) Client 對(duì)象.在此建議使用 rest api,兼容性好,只有吞吐量非常大才值得考慮序列化的開(kāi)銷(xiāo),顯然搜索并不是高吞吐量的業(yè)務(wù).
觀察bulk 請(qǐng)求在不同節(jié)點(diǎn)上的處理情況,通過(guò)cat 接口觀察 bulk 線(xiàn)程池和隊(duì)列情況,是否存在不均:
|
1 |
|
索引過(guò)程調(diào)整和優(yōu)化
自動(dòng)生成 doc ID
分析 es 寫(xiě)入流程可以看到,寫(xiě)入 doc 時(shí)如果是外部指定了 id,es 會(huì)先嘗試讀取原來(lái)doc的版本號(hào), 判斷是否需要更新,使用自動(dòng)生成 doc id 可以避免這個(gè)環(huán)節(jié).
調(diào)整字段 Mappings
字段的 index 屬性設(shè)置為: not_analyzed,或者 no
對(duì)字段不分詞,或者不索引,可以節(jié)省很多運(yùn)算,降低 CPU 占用.尤其是 binary 類(lèi)型,默認(rèn)情況下占用 CPU 非常高,而這種類(lèi)型根本不需要進(jìn)行分詞做索引.
單個(gè) doc 在建立索引時(shí)的運(yùn)算復(fù)雜度,最大的因素 不在于 doc 的字節(jié)數(shù)或者說(shuō)某個(gè)字段 value 的長(zhǎng)度,而是字段的數(shù)量. 例如在滿(mǎn)負(fù)載的寫(xiě)入壓力測(cè)試中,mapping 相同的情況下,一個(gè)有10個(gè)字段,200字節(jié)的 doc, 通過(guò)增加某些字段 value 的長(zhǎng)度到500字節(jié),寫(xiě)入 es 時(shí)速度下降很少,而如果字段數(shù)增加到20,即使整個(gè) doc 字節(jié)數(shù)沒(méi)增加多少,寫(xiě)入速度也會(huì)降低一倍.
使用不同的分析器:analyzer
不同的分析器在索引過(guò)程中運(yùn)算復(fù)雜度也有較大的差異
調(diào)整_source 字段
_source 字段用于存儲(chǔ) doc 原始數(shù)據(jù),對(duì)于部分不需要存儲(chǔ)的字段,可以通過(guò) includes excludes 來(lái)過(guò)濾,或者將 _source 禁用,一般用于索引和數(shù)據(jù)分離
這樣可以降低 io 的壓力,不過(guò)實(shí)際場(chǎng)景大多數(shù)情況不會(huì)禁用 _source ,而即使過(guò)濾掉某些字段,對(duì)于寫(xiě)入速度的提示效果也不大,滿(mǎn)負(fù)荷寫(xiě)入情況下,基本是CPU 先跑滿(mǎn)了,瓶頸在于 CPU.
禁用 _all 字段
_all 字段默認(rèn)是開(kāi)啟的,其中包含所有字段分詞后的關(guān)鍵詞,作用是可以在搜索的時(shí)候不指定特定字段,從所有字段中檢索.如果你不需要這個(gè)特性,可以禁用 _all,可以小幅的降低CPU 壓力,對(duì)速度影響并不明顯.
對(duì)于 Analyzed 的字段禁用 Norms
Norms 用于在搜索時(shí)計(jì)算 doc 的評(píng)分,如果不需要評(píng)分,可以禁用他:
|
1 |
|
index_options 設(shè)置
index_options 用于控制在建立倒排索引過(guò)程中,哪些內(nèi)容會(huì)被添加到倒排,例如 doc數(shù)量,詞頻,positions,offsets等信息,優(yōu)化這些設(shè)置可以一定程度降低索引過(guò)程中運(yùn)算任務(wù),節(jié)省 CPU 占用率
不過(guò)實(shí)際場(chǎng)景中,通常很難確定業(yè)務(wù)將來(lái)會(huì)不會(huì)用到這些信息,除非一開(kāi)始方案就明確這樣設(shè)計(jì)的
方法比結(jié)論重要
當(dāng)面對(duì)一個(gè)系統(tǒng)性問(wèn)題的時(shí)候,往往是多種因素造成的,在處理集群的寫(xiě)入性能問(wèn)題上,先將問(wèn)題分解,在單臺(tái)上分析調(diào)整最高能力到某種系統(tǒng)資源達(dá)到極限,其中觀察利用率,io block,線(xiàn)程切換,堆棧狀態(tài)等,解決局部問(wèn)題,在此基礎(chǔ)上解決整體問(wèn)題會(huì)容易很多
最后
jvm 參數(shù)除了 Xmx,Xms 其他盡量使用默認(rèn),一些看起來(lái)比較合理的參數(shù)實(shí)際效果可能適得其反。
共享下我的配置:
template-base
elasticsearch
參考鏈接
https://doc.yonyoucloud.com/doc/mastering-elasticsearch/chapter-3/36_README.html
https://qbox.io/blog/maximize-guide-elasticsearch-indexing-performance-part-1
https://qbox.io/blog/maximize-guide-elasticsearch-indexing-performance-part-2
https://qbox.io/blog/maximize-guide-elasticsearch-indexing-performance-part-3
相關(guān)文章:
elasticsearch 一次長(zhǎng)時(shí)間 FGC 問(wèn)題分析
elasticsearch 寫(xiě)流程
elasticsearch 機(jī)制和架構(gòu)
(轉(zhuǎn)載請(qǐng)注明作者和出處 easyice.cn ,請(qǐng)勿用于任何商業(yè)用途)
總結(jié)
以上是生活随笔為你收集整理的Elasticsearch 调优之 写入速度优化到极限的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何构建高效可信的持续交付能力,华为云有
- 下一篇: 计算机组成原理7-CISC和RISC、G