Elasticsearch學習系列七(Es分散式集群)
核心概念
集群(Cluster)
一個Es集群由多個節點(Node)組成,每個集群都有一個共同的集群名稱作為標識
節點(Node)
一個Es實例就是一個Node。Es的配置文件中可以通過node.master、node.data來設置節點類型。
Es的節點有如下幾個類型:
- 主節點
master節點在每個集群中有且只有一個。master節點應該只承擔輕量級的任務:如創建刪除索引、分片均衡等
# 設置為true
node.master: true
# 盡量設置主節點不為數據節點,提⽰效率
node.data: false
- 候選節點
和主節點的配置相同,可以在選舉時被選舉為主節點
- 數據節點
這樣的節點主要負責數據的存儲和查詢
# 是否為候選節點
node.master: false
# 是否為數據節點
node.data: true
- 協調節點(coordinating)
每⼀個節點都隱式的是⼀個協調節點,協調節點既不當候選節點,也不作為數據節點,僅負責負載均衡,進⾏投票
# 是否為候選節點
node.master: false
# 是否為數據節點
node.data: false
- 僅投票節點(voting)
設置為僅投票節點後即使配置了data.master=true,也不會參選,但是仍然可以作為數據節點
# 是否為投票節點
Node.voting_only = true
- 默認
Es節點默認配置既是候選節點又是數據節點,這樣節點一旦被選舉為master,壓力還是比較大的。
分片
當有大量的文檔時,由於記憶體的限制、磁碟處理能力不足、無法足夠快的響應客戶端的請求等,一個節點可能不夠。這種情況下,數據可以分為較小的分片。每個分片放到不同的伺服器上。當你查詢的索引分布在多個分片上時,ES會把查詢發送給每個相關的分片,並將結果組合在一起,而應用程式並不知道分片的存在。一個索引會有一個或多個分片。
副本
為提高查詢吞吐量或實現高可用性,可以使用分片副本。副本是一個分片的精確複製,每個分片可以有零個或多個副本。ES中可以有許多相同的分片,其中之一被選擇更改索引操作,這種特殊的分片稱為主分片。當主分片丟失時,集群將副本提升為新的主分片。
分片和副本的區別:
當你分片設置為5,數據量為30G時,es會自動幫我們把數據均衡地分配到5個分片上,即每個分片大概有6G數據,當你查詢數據時,ES會把查詢發送給每個相關的分片,並將結果組合在一起。
而副本,就是對分布在5個分片的數據進行複製。因為分片是把數據進行分割而已,數據依然只有一份,這樣的目的是保障查詢的高效性,副本則是多複製幾份分片的數據,這樣的目的是保障數據的高可靠性,防止數據丟失。
Es分散式架構
特性:
- 高擴展性:體現在Elasticsearch添加節點非常簡單,新節點無需做複雜的配置,只要配置好集群資訊將會被集群自動發現
- 高可用性:因為Elasticsearch是分散式的,每個節點都會有備份,所以宕機一兩個節點也不會出現問題,集群會通過備份進行自動復盤
- 實時性:使用倒排索引來建立存儲結構,搜索時常在百毫秒內就可完成
分層結構:
第一層:Gateway
Es支援的索引快照的存儲格式,es默認是先把索引存放在記憶體中,當記憶體滿了之後再持久化到本地磁碟。gateway對索引快照進行存儲,當es關閉再啟動的時候,它就會從這個gateway裡面讀取索引數據;支援的格式有:本地的Local FileSystem、分散式的Shard FileSystem、Hadoop的文件系統HDFS、Amazon的S3.
第二層:Lucene框架
第三層:Es數據的加工處理方式
Index Module(創建Index模組)、Search Module(搜索模組)、Mapping(映射)、River代表es的一個數據源(運行在Elasticsearch集群內部的一個插件,主要用來從外部獲取獲取異構數據,然後在Elasticsearch里創建索引;常見的插件有RabbitMQ River、Twitter River)
第四層:Es發現機制、腳本
Discovery 是Elasticsearch自動發現節點的機制的模組,Zen Discovery和 EC2 discovery。
EC2:亞馬遜彈性計算雲 EC2discovery主要在亞馬雲平台中使用。
Zen:相當於solrcloud中的zookeeper。zen Discovery 從功能上可以分為兩部分,第一部分是集群剛啟動時的選主,或者是新加
入集群的節點發現當前集群的Master。第二部分是選主完成後,Master 和 Folower 的相互探活。
Scripting 是腳本執行功能,有這個功能能很方便對查詢出來的數據進行加工處理
3rd Plugins 表示Elasticsearch支援安裝很多第三方的插件,例如elasticsearch-ik分詞插件、elasticsearch-sql sql插件
第五層:Es的交互方式
有Thrift、Memcached、Http三種協議,默認的是用Http協議傳輸
第六層:Es的API支援模式
RESTFul Style API風格的API介面標準是當下十分流行的。Elasticsearch作為分散式集群,客戶端到服務端,節點與節點間通訊有TCP和Http通訊協議,底層實現為Netty框架
集群規劃
- 我們需要多個規模的集群
計算的依據:Es JVM heap最大可以設置32G,30G heap大概能處理10T,如果記憶體很大的機器,可以在一台機器上運行多個ES節點。
兩類應用場景:
-
用於構建業務搜索功能模組,且多是垂直領域的搜索。數據量幾千萬到十億級別。一般2-4台機器的規模
-
用於大規模數據的實時聯機處理分析,如ELK等,數據規模可能達千億或更多。一般幾十到上百節點的規模
- 如何避免腦裂
6.x和之前版本 盡量避免腦裂,需要添加最小數量的主節點配置:
discovery.zen.minimum_master_nodes: (有master資格節點數/2) + 1
這個參數控制的是,選舉主節點時需要看到最少多少個具有master資格的活節點,才能進行選舉。官方推薦的值是(N/2)+1,其中N是具有master資格的節點的數量。
在新版7.X的ES中,對es的集群發現系統做了調整,不再有discovery.zen.minimum_master_nodes這個控制集群腦裂的配置,轉而由集群自主控制,並且新版在啟動一個新的集群的時候需要有cluster.initial_master_nodes初始化集群列表。
常用做法(中大規模集群):
- Master 和 dataNode 角色分開,配置奇數個master
- discovery.zen.ping.multicast.enabled: false —— 關閉多播發現機制,默認是關閉的
- 延長ping master的等待時長
discovery.zen.ping_timeout:30(默認值是3秒)——其他節點ping主節點多久時間沒有響應就認為主節點不可用了。
es7中換成了 discovery.request_peers_timeout
- 索引應該設置多少個分片
分片數指定後不可變,除非重建索引。
參考原則:
ElasticSearch推薦的最大JVM堆空間是30~32G,所以把你的分片最大容量限制為30GB, 然後再對分片數量做合理估算. 例如: 你認為你的數據能達到200GB, 推薦你最多分配7到8個分片。
在開始階段, 一個好的方案是根據你的節點數量按照1.5~3倍的原則來創建分片. 例如,如果你有3個節點,則推薦你創建的分片數最多不超過9(3×3)個。當性能下降時,增加節點,ES會平衡分片的放置。
對於基於日期的索引需求, 並且對索引數據的搜索場景非常少. 也許這些索引量將達到成百上千, 但每個索引的數據量只有1GB甚至更小.對於這種類似場景,建議只需要為索引分配1個分片。如日誌管理就是一個日期的索引需求,日期索引會很多,但每個索引存放的日誌數據量就很少。
- 分片應該設置幾個副本
為了保證高可用,副本數設置為2即可。要求集群至少要有3個節點,來分開存放主分片、副本。如發現並發量大時,查詢性能會下降,可增加副本數,來提升並發查詢能力。
注意:新增副本時主節點會自動協調,然後拷貝數據到新增的副本節點,副本數是可以隨時調整的。
分散式集群調優策略
寫調優
- 首次導入,副本數設為0
如果是集群首次灌入數據,可以將副本數設置為0,寫入完畢再調整回去,這樣副本分片只需要拷貝,節省了索引過程。
- 自動生成doc id
如果寫入doc時指定了id,則Es會先嘗試讀取原來doc的版本號,以判斷是否需要更新。這會涉及一次讀取磁碟的操作,通過自動生成doc id就可以避免這個環節。
- 合理設置mappings
- 將不需要建立索引的欄位index屬性設置為not_analyzed或no。對欄位不分詞,或者不索引,可以減少很多運算操作,降低CPU佔用。尤其是binary類型,默認情況下佔用CPU非常高,而這種類型進行分詞通常沒有什麼意義。
- 減少欄位內容長度,如果原始數據的大段內容無須全部建立索引,則可以盡量減少不必要的內容。
- 使用不同的分析器(analyzer),不同的分析器在索引過程中運算複雜度也有較大的差異。
- 調整_source欄位
source欄位用於存儲doc原始數據,對於部分不需要存儲的欄位,可以通過includes或excludes過濾
- 對analyzed的欄位禁用norms
Norms用於搜索時計算評分,如果不需要評分的場景,可以禁用掉
"title": {
"type": "string",
"norms": {
"enabled": false
}
- 調整索引的刷新間隔
該參數默認為1s,強制ES每秒創建一個新的segment,從而保證新寫入的數據近實時的可見,可被搜索到。比如該參數被調整為30S,降低了刷新操作的頻率,則可省一些系統資源
PUT /my_index/_settings
{
"index" : {
"refresh_interval": "30s"
}
- 批處理
批處理就是把多個index操作請求合併到一個batch中去處理
- Document的路由處理
當對一批中的documents進行index操作時,該批index操作所需要的執行緒的個數由要寫入的目的分片數決定。
上圖中,有2批documents寫入ES,每批都需要寫入4個shard,所以總共需要8個執行緒。如果能減少shard的個數,那麼耗費的執行緒個數也會減少。例如下圖,兩批中每批的shard個數都只有2個,總共執行緒消耗個數4個,減少一半。
默認的routing就是id,也可以在發送請求的時候,手動指定一個routing value,比如說put/index/doc/id?routing=user_id
值得注意的是執行緒數雖然降低了,但是單批的處理耗時可能增加了。和提高刷新間隔方法類似,這有可能會延長數據的實時性
讀優化
- 數據分組
很多人拿Es存儲日誌,日誌的索引管理方式一般是基於日期的,如天、周、年。
當搜索單天的數據,只需要查詢一個索引的shards就可以。當需要查詢多天的數據時,需要查詢多個索引的shards。這種方案其實和資料庫的分表、分庫、分區查詢方案思路相似
- 使用Filter代替Query
搜索時使用Query,需要為Document的相關度打分。使用Filter,沒有打分環節,所以理論上更快。
- ID欄位定義為keyword
一般情況,如果ID欄位不會被用作Range類型的搜索欄位,都可以定義為keyword類型。這是因為keyword會被優化,以便進行terms查詢。Integers等數字類的mapping類型,會被優化來進行range類型搜索。將integers改成keyword類型之後,搜索性能大約能提升30%
- 別讓用戶的無約束輸入拖累Es性能
避免用戶輸入很多OR語句或者通配符*開頭的這種語句。