ElasticSearch 分佈式集羣

公號:碼農充電站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.masterfalse 來禁止成爲 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 節點上的 p0R1 分片,會被分配到 Node2Node3 上。

在這裏插入圖片描述

集羣調整完畢後,會重新恢復到 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 操作(插入,更新,刪除)的流程:

  1. 客戶將文檔的 Write 請求發送到 Coordinating 節點(Coordinating 節點負責處理客戶請求,而不是 Master 節點)。
  2. Coordinating 節點通過 Hash 算法找到該文檔的主分片
  3. 在主分片上進行 Write 操作,主分片 Write 成功後,將該 Write 請求發送到所有的副本分片
  4. 所有副本分片進行相應的 Write 操作,成功後,將結果返回給主分片。
  5. 主分片將所以的執行結果反饋給 Coordinating 節點。
  6. 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 的方式,到相應的分片獲取具體的文檔信息,並返回給用戶。

這兩個階段合稱爲 Query Then Fetch

在這裏插入圖片描述

8.2,Query Then Fetch 的問題

在這裏插入圖片描述

8.3,算分不準的解決辦法

在這裏插入圖片描述

(本節完。)


推薦閱讀:

ElasticSearch 文檔及操作

ElasticSearch 搜索模板與建議

ElasticSearch 聚合分析

ElasticSearch 中的 Mapping

ElasticSearch 數據建模


歡迎關注作者公衆號,獲取更多技術乾貨。

碼農充電站pro

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