公號:碼農充電站pro
主頁:https://codeshellme.github.io
1,ES 的分散式架構
ES 是一個分散式的叢集,具有高可用性和可擴充套件性:
- 高可用性指的是:當某些節點意外當機或者資料丟失的時候,不影響整個叢集的使用。
- 可擴充套件性指的是:當業務資料量增加的時候,可以增加節點的數量,從而增強整個叢集的能力。
ES 叢集
ES 叢集中可以有一個或多個節點,ES 通過叢集名字來區分不同的叢集,叢集名可以通過 cluster.name
進行設定,預設為 "elasticsearch"。
2,ES 的節點型別
ES 的一個節點就是一個 Java 程式,所以一臺機器可以執行一個或多個節點,生產環境建議一臺機器只執行一個節點。
每個節點啟動之後,都會分配一個 UID
,並儲存在 data
目錄下。
每個節點都有節點名字,節點名可通過 node.name
設定。
2.1,Master 節點
Master 節點的職責:
- 處理客戶端的請求。
- 決定分片被分配到哪個節點。
- 負責索引的建立於刪除。
- 維護叢集狀態。
- 等。
叢集的狀態包括:
- 所有的節點資訊
- 所有的索引及其 Mapping 和 Setting 資訊
- 分片的路由資訊
所有的節點有儲存了叢集的狀態資訊,但只有主節點能夠修改叢集狀態。
2.2,Master-eligible 節點
在 ES 叢集中,只有 Master-eligible 節點可以被選舉為 Master 節點。
每個節點啟動後預設就是 Master-eligible 節點,可以通過設定 node.master
為 false
來禁止成為 Master-eligible 節點。
預設情況下,叢集中的第一個節點啟動後,會將自己選舉為 Master 節點。
叢集中的每個節點都儲存了叢集的狀態,但只有 Master 節點能夠修改叢集的狀態資訊。
2.3,Data 與 Coordinating 節點
用於儲存 ES 資料的節點,就是 Data 節點,它對資料擴充套件起到了至關重要的作用。
Coordinating 節點叫做協調節點,它負責接收 Client 的請求,將請求分發到合適的節點,並最終彙總結果返回給 Client。
在 ES 中,所有的節點都是 Coordinating 節點。
2.4,Ingest 節點
Ingest 節點用於對資料預處理,通過新增一些 processors 來完成特定的處理。
Ingest 節點是在 ES 5.0 後引入的一種節點型別,可以達到一定的 Logstash 的功能。
預設情況下,所有的節點都是 Ingest 節點。
2.5,配置節點型別
理論上,一個節點可以扮演過多個角色,但生產環境中,建議設定單一角色。
節點的型別可以通過下面引數進行配置:
節點型別 | 配置引數 | 預設值 |
---|---|---|
Master-eligible | node.master | true |
Data Node | node.data | true |
Ingest Node | node.ingest | true |
Coordinating Node | 無 | 設定上面 3 個都為 false |
3,叢集的健康狀態
我們可以通過下面的 API 來檢視整個叢集的健康狀態:
叢集有 3 種級別的健康狀態:
green
:所有的主分片與副本分片都正常。yellow
:所有的主分片都正常,某些副本分片不正常。red
:部分主分片不正常。
我們也可以通過 Kibana 中的索引管理,來檢視每個索引的健康狀態:
索引的狀態級別與叢集的狀態級別一致。
4,腦裂問題
腦裂問題是分散式系統中的經典問題。
腦裂問題指的是,當出現網路故障時,一些節點無法與另一些節點連線,這時這兩大部分節點會各自為主;當網路恢復時,也無法恢復成一個整體。
如何避免腦裂問題
要限定一個選舉條件,設定 Quorum(仲裁):
- Quorum = (master 節點總數 / 2)+ 1
只有當 Master eligible 節點數大於 Quorum 時,才能進行選舉。
在 ES 7.0 之前,為了避免腦裂問題,需要手動設定 discovery.zen.minimum_master_nodes
為 Quorum。
在 ES 7.0 之後,ES 會自己處理腦裂問題,不需要使用者處理。
5,ES 中的分片
ES 中的分片(Shard)用於儲存資料,是儲存的最小單元。
分片有兩種:主分片(Primary Shard)和副本分片(Replica Shard),副本分片是主分片的拷貝。
主分片用於資料水平擴充套件的問題,主分片數在索引建立時指定,之後不允許修改。
副本分片用於解決資料高可用的問題,副本分片數可以動態調整。
分片數可以通過索引的 setting
進行設定,比如:
PUT /index_name
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
其中 number_of_shards
表示主分片數,number_of_replicas
表示每個主分片的副本分片數。
如果一個叢集有 3 個資料節點,某個索引有 3 個主分片,1 一個副本分片,那麼它的節點分佈會像下面這樣:
其中藍色框為主分片,白色框為副本分片。
ES 在分配主副分片時,會將副本分片與主分片應該在不同的節點上。
主分片和副本分片分別分佈到不同的資料節點上,這樣的話,如果有某個資料節點當機,也不會影響整個系統的使用。
ES 7.0 開始,預設的主分片數為 1,預設的副本分片數為 0。在生產環境中,副本分片數至少為 1。
5.1,生產環境如何設定分片數
分片數設定不合理引發的問題:
5.2,叢集節點的變化
根據這樣的配置(3 個主分片,1 個副本分片),如果只有一個節點,則會導致副本分片無法分配(ES 會將主副分片分配在不同的節點上),叢集狀態為 yellow。
如果此時增加一個資料節點,那麼副本分片就得以分配,叢集具備了故障轉移能力,叢集狀態轉為 green。
如果此時再增加一個資料節點,那麼主節點會重新分配分片的分佈。同時,叢集的整體能力也得到了提升。
5.3,故障轉移
如果此時有一個節點發生故障,比如主節點發生了故障:
此時叢集的狀態會變為 yellow,然後會重新選舉主節點(假設選舉了 Node2 為主節點),並且原來的 Node1 節點上的 p0 和 R1 分片,會被分配到 Node2 和 Node3 上。
叢集調整完畢後,會重新恢復到 green 狀態。
6,分片的內部原理
ES 中的一個分片對應了 Lucene 中的一個 Index。
6.1,Lucene Index
在 Lucene 中,單個倒排索引檔案稱為 Segment。
Segment 是不可變的,當有新的文件寫入時,會生成新的 Segment(放在檔案系統快取中)。
多個 Segment 彙總在一起稱為 Lucene 中的 Index,也就是 ES 中的分片。
6.2,Refresh 重新整理
ES 的文件在寫入時,會先放在 Index Buffer
(記憶體) 中,當 Index Buffer 的空間被佔用到一定程度/時間週期後,會 Refresh 到 Segment 中,Index Buffer 則會被清空。
Refresh 的重新整理頻率可以通過 index.refresh_interval 引數進行設定,預設為 1 秒。
或者當 Index Buffer 被佔用到 JVM 的 10%(預設值),也會觸發 Refresh。
當文件被 Refresh 到 Segment 後,就可以被 ES 檢索到了。
6.3,Transaction log
寫入文件時,會先放在 Index Buffer
中,而 Index Buffer 是在記憶體中,為了防止記憶體意外(比如斷電)丟失,在寫入 Index Buffer 的同時,也會寫到 Transaction log(磁碟)中。
一個 Transaction log 預設是 512M。
6.4,Flush 操作
ES 的 Flush 會觸發以下操作:
- 呼叫 Refresh
- 呼叫 fsync,將檔案系統快取中的 Segment 寫入磁碟。
- 清空 Transaction log。
Flush 操作預設 30 分鐘呼叫一次,或者當 Transaction log 滿(預設 512 M)時也會觸發 Flush。
6.5,Merge 合併
當越來越多的 Segment 被寫入到磁碟後,磁碟上的 Segment 會變得很多,ES 會定期 Merge 這些 Segment。
文件的刪除操作並不會馬上被真正的刪除,而是會寫入 del 檔案中,Merge 操作也會刪除該檔案。
Merge 操作可以由 ES 自動觸發,也可以手動強制 Merge,語法如下:
POST index_name/_forcemerge
7,文件的分散式儲存
文件會均勻分佈在分片上,充分利用硬體資源,避免資源利用不均。
文件到分片的路由演算法:
shard_index = hash(_routing) % number_of_primary_shards
- Hash 演算法可以保證文件均勻的分散到分片上。
- 預設的
_routing
值為文件 id。 _routing
的值也可以自行指定。
正是因為文件的路由演算法是基於主分片數來計算的,所以主分片數一旦確定以後,就不能修改。
_routing 的設定語法如下:
POST index_name/_doc/doc_id/routing=xxx
{
# 文件資料
}
文件的 Write 操作(插入,更新,刪除)的流程:
- 客戶將文件的 Write 請求傳送到 Coordinating 節點(Coordinating 節點負責處理客戶請求,而不是 Master 節點)。
- Coordinating 節點通過 Hash 演算法找到該文件的主分片。
- 在主分片上進行 Write 操作,主分片 Write 成功後,將該 Write 請求傳送到所有的副本分片。
- 所有副本分片進行相應的 Write 操作,成功後,將結果返回給主分片。
- 主分片將所以的執行結果反饋給 Coordinating 節點。
- Coordinating 節點將最終的結果反饋給客戶端。
8,分散式查詢及相關性算分
8.1,Query Then Fetch 過程
ES 的搜尋過程分兩個階段:
- Query 階段:
- 使用者將查詢請求傳送到 Coordinating 節點,Coordinating 節點會隨機選擇 N(主分片數) 個分片,傳送查詢請求。
- 收到查詢請求的分片執行查詢,並進行排序。然後每個分片都會返回
From + Size
個排好序的文件 ID 和排序值(score),給 Coordinating 節點。
- Fetch 階段:
- Coordinating 節點會將從所有分片得到的文件重新排序,重新得到
From + Size
個文件的 ID。 - Coordinating 節點以
Multi Get
的方式,到相應的分片獲取具體的文件資訊,並返回給使用者。
- Coordinating 節點會將從所有分片得到的文件重新排序,重新得到
這兩個階段合稱為 Query Then Fetch。
8.2,Query Then Fetch 的問題
8.3,算分不準的解決辦法
(本節完。)
推薦閱讀:
歡迎關注作者公眾號,獲取更多技術乾貨。