(Elasticsearch)ES寫入性能優化方案

在ES的默認設置下,是綜合考慮數據的可靠性,搜索實時性,寫入速度等因素的。當離開默認設置,追求極致寫入速度時,很多是以犧牲可靠性和搜索實時性爲代價的。有時候,業務上對數據可靠性和搜索實時性要求不高,反而對寫入速度要求很高,此時可以調整一些策略,最大化寫入速度。

綜合來說可以從以下幾個方面入手:

  • 加大translog flush間隔,目的是降低iops,writeblock (可靠性降低)
  • 加大index refresh間隔,除了降低I/O,更重要的是降低segment merge頻率
  • 調整bulk請求(批處理)
  • 優化磁盤間的任務均勻情況,將shard儘量均勻分佈到物理機各個磁盤
  • 優化節點間的任務分佈,將任務儘量均勻地發到各節點
  • 優化Lucene層建立索引的過程,目的是降低CPU佔用率,例如,禁用_all字段

translog flush

ES請求進行,先會寫入到translog文件中,在ES 2.x開始,默認情況下,translog的持久化策略爲:每個請求都“flush”。對應配置

index.translog.durability:request

這會影響ES寫入的最大因素。但是隻有這樣,寫操作纔可能是最可靠的,如果系統允許接收一定概率的數據丟掉,則可以調整translog持久化策略爲週期性和一定大小的時候“flush”。

設置translog策略爲異步,時間120s

index.translog.durability:async

設置刷盤時間爲120s,默認5s

index.translog.sync_interval:120s

超過設置大小會導致refresh操作,產生新的Lucene分段。默認爲512MB

index.translog.flush_threshold_size:1024mb

索引刷新間隔refresh_interval

默認情況下索引的refresh_interval爲1秒,這意味着數據寫如1秒後就可以被搜索到,每次索引的refresh會產生一個新的Lucene段(segment),試想以下,如果segment過多會怎麼樣,因此ES 會進行segment merge 段合併,如果不需要這麼高的搜索實時性,可以適當降低refresh週期,如下:

index.refresh_interval:120s

segment段合併優化

segment merge 操作對系統I/O和內存佔用都比較高,從ES 2.0 開始,merge操作不再由ES 控制,而是由Lucene 控制,改爲以下

index.merge.scheduler.max_thread_count

index.merge.policy.*

最大線程數max_thread_count默認值是:

Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2))

這是一個比較理想的值,如果只是一塊硬盤而非SSD,則應該設置爲1,因爲在旋轉存儲介質上併發寫,由於尋址原因,只會降低寫入速度。

merge策略index.merge.policy有三種

  • tiered(默認)
  • log_byete_size
  • log_doc

索引創建時合併策略就已確定,不能進行修改,但是可以動態更新策略參數,可以不做此項調整。

如果堆棧經常有很多merge,則可以嘗試調整以下策略配置:

index.merge.policy.segments_per_tier

該屬性指定了每層分段的數量,取值越小最終segment越少,因此需要merge操作越多,可以考慮適當增加值,默認10,其應該大於等於index.merge_at_once

index.merge.policy.max_merged_segment

指定單個segment最大容量,默認5GB,可以適當降低

index buffer 

indexing buffer 在爲doc建立索引時使用,當緩衝滿時會刷入磁盤,生成一個新的segment,這是除了refresh_interval 刷新索引外,另一個生成新segment的機會。每個shard有自己的indexing buffer,下面的這個buffer大小的配置需要除以這個節點上索引shard的數量:

indices.memory.index_buffer_size

默認是整個堆空間的10%

indices.memory.min_index_buffer_size

默認48MB

indices.memory.max_index_buffer_size

默認無限制

在執行大量的索引操作時,indices.memory.index_buffer_size的默認設置可能不夠,這和可用堆內存,單節點上的shard數量相關,可以考慮適當增大該值。

使用bulk請求

批量寫比一個索引請求只寫單個文檔的效率高得多,但是要注意bulk請求得整體字節數不要太大,太大可能給集羣帶來內存壓力,因此每個請求最好避免超過幾十MB,即使較大得請求看上去執行可能更好。

索引建立過程屬於CPU密集型任務,應該使用固定大小的線程池,來不及處理的任務放入隊列。這樣可以減少上下文的切換帶來的性能消耗,隊列大小要適當,過大的隊列導致較高的GC壓力,並可能導致FGC頻繁發生。

bulk寫請求是一個長任務,爲了給系統增加足夠的寫入 壓力,寫入過程應該多個客戶端,多個線程冰箱執行。

磁盤間的任務均衡

ES 在分配shard的時候,落到各個磁盤的shard可能並不均勻,這種不均勻可能導致某些磁盤繁忙,對寫入性能會產生一定的影響

節點間的任務均衡,爲了節點間的任務儘量均衡,數據寫入客戶端應該把bulk請求輪詢發送到各個節點。

索引過程調整和優化

1.自動生成docID(避免ES對自定義ID驗證的操作)

2.調整字段Mapping

  • 減少不必要的字段數量
  • 將不需要建立索引字段的index屬性設置爲not_analyzed或no。對字段不分詞或不建立索引,減少相應的操作,特別是binary類型
  • 減少字段內容長度
  • 使用不同的分析器(analyzer),不同分析器之間的運算複雜度也不相同

3.調整_source字段

_source字段用於存儲doc原始數據,對於部分不需要存儲的字段,可以通過includes excludes過濾,或者禁用_source,一般實際場景不會禁用

4.禁用_all

從ES 6.0開始,_all字段默認不啓用,_all字段中包含所有字段分詞後的關鍵詞,作用是可以搜索的時候不指定特定字段,從所有字段所有中減少。

5.對Analyzed的字段禁用Norms

 Norms用於在搜索時計算doc的評分,如果不需要評分,則可以將其禁用:

"title":{"type":"string","norms":{"enabled":false}}

6.index_options設置

index_options用於控制在建立倒排索引過程中,哪些內容會被添加到倒排索引中,例如,doc數量,詞頻,positions,offsets等信息,優化這些設置可以一定程度上降低索引過程中的計算任務,接收CPU佔用率(注:實際場景一般不會用,除非方案一開始很明確)

參考配置

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章