Elasticsearch 叢集調優建議
生產環境叢集搭建建議
1.ES設定儘量簡潔
elasticsearch.yml
中儘量只寫必備的引數,其他可以通過api動態設定的引數都通過api來設定
動態設定的引數有transient
和persistent
兩種設定,前者在叢集重啟後會丟失,後者不會,但兩種設定都會覆蓋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自動完成
其他優化
- 副本設定為0,寫入完畢再增加
- 合理設計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大小也可以得到分片數