1. 程式人生 > >Elasticsearch 叢集調優建議

Elasticsearch 叢集調優建議

生產環境叢集搭建建議

1.ES設定儘量簡潔
elasticsearch.yml中儘量只寫必備的引數,其他可以通過api動態設定的引數都通過api來設定
動態設定的引數有transientpersistent兩種設定,前者在叢集重啟後會丟失,後者不會,但兩種設定都會覆蓋elasticsearch.yml中的配置。

PUT /_cluster/settings
{
  "persistent": {
    "discovery.zen.minimum_master_nodes":2
  },
  "transient": {
    "indices.store.throttle.max_bytes_per_sec"
:"50mb" } }

2.腦裂問題
解決方案:僅在可選舉master-eligible節點數大於等於quorum時才可以進行master選舉

quorum=master-eligible節點數/2 +1,
例如3個master-eligible節點時,quorum為2
設定discovery.zen.minimum_master_nodes為quorum即可避免腦裂

3.關於JVM記憶體設定

  • 不要超過31GB
  • 預留一半記憶體給操作系,用來做檔案快取

具體大小根據該node要儲存的資料量來估算,為了保證效能,在記憶體和資料量間有一個建議的比例:

  • 搜尋類專案的比例建議在1:16以內
  • 日誌類專案的比例建議在1:48~1:96

假設總資料量大小為1TB,3個node,1個副本,那麼每個node要儲存的資料量為2TB/3=666GB,即700GB左右,做20%的預留空間,每個node要儲存大約850GB的資料。

  • 如果是搜尋類專案,每個node記憶體大小為850GB/16=53GB,大於31GB。31*16=496,即每個node最多儲存496GB資料,所以需要至少5個node
  • 如果是日誌型別專案,每個node記憶體大小為850GB/48=18GB,因此3個節點足夠

寫效能優化

目標是增大寫吞吐量-EPS(Event Per Second)越高越好
優化方案:

  • 客戶端:多執行緒寫,批量寫
  • ES:在高質量資料建模的前提下,主要是在refresh、translog和flush之前做文章。

ES寫資料分為三個過程:

  • refresh
  • translog
  • flush

refresh

segment寫入磁碟的過程很耗時,可以藉助檔案系統快取的特性,先將segment在快取中建立並開放查詢來查詢來進一步提升實時性,該過程在es中被稱為refresh

在refresh之前文件會先儲存在一個buffer中,refresh時將buffer中的所有文件清空並生成segment。

es預設每1秒執行一次refresh,因此文件的實時性被提高到1秒,這也是es被稱為近實時(Near Real Time)的原因。

Lucene構建的單個倒排索引稱為segment,合在一起稱為Index,與ES中的Index概念不同,ES中的一個shard對應一個Lucene Index。

優化: 目標為降低refresh的頻率

  • 增大refresh_interval,降低實時性,以增大一次refresh處理的文件數,預設是1s,設定為-1直接禁止自動refresh
  • 增大index buffer size,引數為indices.memory.index_buffer_size(靜態引數,需要設定在elasticsearch.yml中)預設為10%。

translog

如果在記憶體中的segment還沒有寫入磁碟前發生宕機,那麼其中的文件就無法恢復了,如何解決這個問題?
es引入translog機制。寫入文件到buffer時,同時將該操作寫入translog。

translog檔案會即時寫入磁碟(fsync),6.x預設每個請求都會落盤,可以修改為每5秒寫一次,這樣風險便是丟失5秒內的資料,相關配置為index.translog.*

es啟動時會檢查translog檔案,並從中恢復資料

優化: 目標是降低translog寫磁碟頻率,從而提高寫效率,但會降低容災能力

  • index.translog.durability設定為async,index.translog.sync_interval設定需要的大小,比如120s,那麼translog會改為每120s寫一次磁碟
  • index.translog.flush_threshold_size預設為512mb。即translog超過該大小時會觸發一次flush,那麼調大該大小可以避免flush的發生

flush

flush負責將記憶體中的segment寫入磁碟,主要做如下工作:

  • 將translog寫入磁碟
  • 將index buffer清空,其中的文件生成一個新的segment,相當於一個refresh操作
  • 更新commit point並寫入磁碟
  • 執行fsync操作,將記憶體中的segment寫入磁碟
  • 刪除舊的translog檔案

Lucene有一個專門的檔案來記錄所有的segment資訊,稱為commit point

優化: 目標為降低flush的次數,在6.x可優化的點不多,多為es自動完成

其他優化

  1. 副本設定為0,寫入完畢再增加
  2. 合理設計shard數,並保證shard均勻地分配在所有node上,充分利用所有node的資源

index.routing.allocation.total_shards_per_node限定每個索引在每個node上可分配的總主副分片數

例如:5個node,某索引有10個主分片,1個副本,上述值應該設定為多少?

(10+10)/5=4
實際要設定為5個,防止在某個node下線時,分片遷移失敗的問題。

主要為index級別的設定優化,以日誌場景舉例,一般會有如下索引的設定:
這裡寫圖片描述

讀效能優化

讀效能主要受以下幾方面影響:

  • 資料模型是否符合業務模型?
  • 資料規模是否過大?
  • 索引陪孩子是否優化?
  • 查詢語句是否優化?

高質量的資料建模是優化的基礎:

  • 將需要通過script指令碼動態計算的值提前算好作為欄位儲存到文件中
  • 儘量使得資料模型貼近業務模型

根據不同的資料規模設定不同的SLA

  • 上萬條資料與上千萬條資料效能肯定存在差異

索引配置調優:

  • 根據資料規模設定合理的主分片數,可以通過測試得到最合適的分片數
  • 設定合理的副本數目,不是越多越好

查詢語句調優:
查詢語句調優主要有以下幾種常見手段:

  • 儘量使用filter上下文,減少算分的場景,由於filter有快取機制,可以極大提升查詢效能
  • 儘量不使用script進行欄位計算或者算分排序等
  • 結合profile、explain API分析慢查詢語句的癥結所在,然後再去優化資料模型

如何設定shard數?

分片問題?
在一個有三個節點組成的es叢集中建立一個有三個分片的test_index索引。

1.此時增加節點是否能夠提高test_index的資料容量?
    不能。因為只有三個分片,已經分佈在3臺節點上,新增的節點無法利用。
2.此時增加副本數是否能提高test_index的讀取吞吐量?
    不能。因為新增的副本也是分佈在這三個節點上,還是利用了同樣的資源。如果要新增吞吐量,還要新增節點。

分片數的設定很重要,需要提前規劃好

  • 過小會導致後續無法通過增加節點實現水平擴容
  • 過大會導致一個節點上分佈過多分片,造成資源浪費,同時會影響查詢效能

es的效能基本是線性擴充套件的,因此我們只要測出1個shard的效能指標,然後根據實際效能需求就能算出需要的shard數。比如單shard寫入eps是1000,而線上eps需求時5000,那麼你需要5個shard。(實際還要考慮副本的情況)

測試一個shard的流程如下:

  • 搭建與生產環境相同配置的單節點叢集
  • 設定一個單分片零副本的索引
  • 寫入實際生產資料進行測試,獲取寫效能指標
  • 針對資料進行查詢請求,獲取讀效能指標

壓測工具可以採用esrally參考連結

壓測的流程還是比較複雜的,如果是搜尋引擎場景,單個shard大小不要超過15GB,如果是日誌場景,單shard大小不要超過50GB(shard越大,查詢效能越低)
此時只要估算出你索引的總資料大小,然後在除以上面單shard大小也可以得到分片數