4.elasticsearch分佈式特性——集羣內的原理

分佈式特性

在本章開頭,我們提到過 Elasticsearch 可以橫向擴展至數百(甚至數千)的服務器節點,同時可以處理PB級數據。我們的教程給出了一些使用 Elasticsearch 的示例,但並不涉及任何內部機制。Elasticsearch 天生就是分佈式的,並且在設計時屏蔽了分佈式的複雜性。

Elasticsearch 在分佈式方面幾乎是透明的。教程中並不要求瞭解分佈式系統、分片、集羣發現或其他的各種分佈式概念。可以使用筆記本上的單節點輕鬆地運行教程裏的程序,但如果你想要在 100 個節點的集羣上運行程序,一切依然順暢。

Elasticsearch 儘可能地屏蔽了分佈式系統的複雜性。這裏列舉了一些在後臺自動執行的操作:

  • 分配文檔到不同的容器 或 分片 中,文檔可以儲存在一個或多個節點中
  • 按集羣節點來均衡分配這些分片,從而對索引和搜索過程進行負載均衡
  • 複製每個分片以支持數據冗餘,從而防止硬件故障導致的數據丟失
  • 將集羣中任一節點的請求路由到存有相關數據的節點

集羣擴容時無縫整合新節點,重新分配分片以便從離羣節點恢復ElasticSearch 的主旨是隨時可用和按需擴容。 而擴容可以通過購買性能更強大( 垂直擴容 ,或 縱向擴容) 或者數量更多的服務器( 水平擴容 ,或 橫向擴容 )來實現。

雖然 Elasticsearch 可以獲益於更強大的硬件設備,但是垂直擴容是有極限的。 真正的擴容能力是來自於水平擴容--爲集羣添加更多的節點,並且將負載壓力和穩定性分散到這些節點中。

對於大多數的數據庫而言,通常需要對應用程序進行非常大的改動,才能利用上橫向擴容的新增資源。 與之相反的是,ElastiSearch天生就是 分佈式的 ,它知道如何通過管理多節點來提高擴容性和可用性。 這也意味着你的應用無需關注這個問題。

一、空集羣

如果我們啓動了一個單獨的節點,裏面不包含任何的數據和 索引,那我們的集羣就是空集羣。

一個運行中的 Elasticsearch 實例稱爲一個 節點,而集羣是由一個或者多個擁有相同 cluster.name 配置的節點組成, 它們共同承擔數據和負載的壓力。當有節點加入集羣中或者從集羣中移除節點時,集羣將會重新平均分佈所有的數據。

當一個節點被選舉成爲  節點時, 它將負責管理集羣範圍內的所有變更,例如增加、刪除索引,或者增加、刪除節點等。 而主節點並不需要涉及到文檔級別的變更和搜索等操作,所以當集羣只擁有一個主節點的情況下,即使流量的增加它也不會成爲瓶頸。 任何節點都可以成爲主節點。我們的示例集羣就只有一個節點,所以它同時也成爲了主節點。

作爲用戶,我們可以將請求發送到 集羣中的任何節點 ,包括主節點。 每個節點都知道任意文檔所處的位置,並且能夠將我們的請求直接轉發到存儲我們所需文檔的節點。 無論我們將請求發送到哪個節點,它都能負責從各個包含我們所需文檔的節點收集回數據,並將最終結果返回給客戶端。 Elasticsearch 對這一切的管理都是透明的。

二、集羣健康

Elasticsearch 的集羣監控信息中包含了許多的統計數據,其中最爲重要的一項就是 集羣健康 , 它在 status 字段中展示爲 green 、 yellow 或者 red 。

curl -X GET "localhost:9200/_cluster/health?pretty=true"
{
  "cluster_name" : "elasticsearch",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 15,
  "active_shards" : 15,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 15,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 50.0
}

status 字段是我們最關心的。

status 字段指示着當前集羣在總體上是否工作正常。它的三種顏色含義如下:

green

所有的主分片和副本分片都正常運行。

yellow

所有的主分片都正常運行,但不是所有的副本分片都正常運行。

red

有主分片沒能正常運行。

三、添加索引

我們往 Elasticsearch 添加數據時需要用到 索引 —— 保存相關數據的地方。 索引實際上是指向一個或者多個物理 分片 的 邏輯命名空間 。

一個 分片 是一個底層的 工作單元 ,它僅保存了 全部數據中的一部分。 在分片內部機制中,我們將詳細介紹分片是如何工作的,而現在我們只需知道一個分片是一個 Lucene 的實例,以及它本身就是一個完整的搜索引擎。 我們的文檔被存儲和索引到分片內,但是應用程序是直接與索引而不是與分片進行交互。

Elasticsearch 是利用分片將數據分發到集羣內各處的。分片是數據的容器,文檔保存在分片內,分片又被分配到集羣內的各個節點裏。 當你的集羣規模擴大或者縮小時, Elasticsearch 會自動的在各節點中遷移分片,使得數據仍然均勻分佈在集羣裏。

一個分片可以是  分片或者 副本 分片。 索引內任意一個文檔都歸屬於一個主分片,所以主分片的數目決定着索引能夠保存的最大數據量。

注意

技術上來說,一個主分片最大能夠存儲 Integer.MAX_VALUE - 128 個文檔,但是實際最大值還需要參考你的使用場景:包括你使用的硬件, 文檔的大小和複雜程度,索引和查詢文檔的方式以及你期望的響應時長。

一個副本分片只是一個主分片的拷貝。 副本分片作爲硬件故障時保護數據不丟失的冗餘備份,併爲搜索和返回文檔等讀操作提供服務。

在索引建立的時候就已經確定了主分片數,但是副本分片數可以隨時修改。

讓我們在包含一個空節點的集羣內創建名爲 blogs 的索引。 索引在默認情況下會被分配5個主分片, 但是爲了演示目的,我們將分配3個主分片和一份副本(每個主分片擁有一個副本分片):

PUT /blogs
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}

拷貝爲 CURL在 SENSE 中查看 

我們的集羣現在是圖 2 “擁有一個索引的單節點集羣”。所有3個主分片都被分配在 Node 1 。

圖 2. 擁有一個索引的單節點集羣

擁有一個索引的單節點集羣

如果我們現在查看集羣健康, 我們將看到如下內容:

{
  "cluster_name": "elasticsearch",
  "status": "yellow", 
  "timed_out": false,
  "number_of_nodes": 1,
  "number_of_data_nodes": 1,
  "active_primary_shards": 3,
  "active_shards": 3,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 3, 
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 50
}

集羣 status 值爲 yellow 

unassigned_shards 沒有被分配到任何節點的副本數。

集羣的健康狀況爲 yellow 則表示全部  分片都正常運行(集羣可以正常服務所有請求),但是 副本 分片沒有全部處在正常狀態。 實際上,所有3個副本分片都是 unassigned —— 它們都沒有被分配到任何節點。 在同一個節點上既保存原始數據又保存副本是沒有意義的,因爲一旦失去了那個節點,我們也將丟失該節點上的所有副本數據。

當前我們的集羣是正常運行的,但是在硬件故障時有丟失數據的風險。

四、添加故障轉移

當集羣中只有一個節點在運行時,意味着會有一個單點故障問題——沒有冗餘。 幸運的是,我們只需再啓動一個節點即可防止數據丟失。

當你在同一臺機器上啓動了第二個節點時,只要它和第一個節點有同樣的 cluster.name 配置,它就會自動發現集羣並加入到其中。 但是在不同機器上啓動節點的時候,爲了加入到同一集羣,你需要配置一個可連接到的單播主機列表。詳細信息請查看最好使用單播代替組播

如果啓動了第二個節點,我們的集羣將會如圖 3 “擁有兩個節點的集羣——所有主分片和副本分片都已被分配”所示。

擁有兩個節點的集羣——所有主分片和副本分片都已被分配

擁有兩個節點的集羣

當第二個節點加入到集羣后,3個 副本分片 將會分配到這個節點上——每個主分片對應一個副本分片。 這意味着當集羣內任何一個節點出現問題時,我們的數據都完好無損。

所有新近被索引的文檔都將會保存在主分片上,然後被並行的複製到對應的副本分片上。這就保證了我們既可以從主分片又可以從副本分片上獲得文檔。

cluster-health 現在展示的狀態爲 green ,這表示所有6個分片(包括3個主分片和3個副本分片)都在正常運行。

{
  "cluster_name": "elasticsearch",
  "status": "green", 
  "timed_out": false,
  "number_of_nodes": 2,
  "number_of_data_nodes": 2,
  "active_primary_shards": 3,
  "active_shards": 6,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100
}

集羣 status 值爲 green 。

我們的集羣現在不僅僅是正常運行的,並且還處於 始終可用 的狀態。

五、水平擴容

怎樣爲我們的正在增長中的應用程序按需擴容呢? 當啓動了第三個節點,我們的集羣將會看起來如圖 4 “擁有三個節點的集羣——爲了分散負載而對分片進行重新分配”所示。

圖 4. 擁有三個節點的集羣——爲了分散負載而對分片進行重新分配

擁有三個節點的集羣

Node 1 和 Node 2 上各有一個分片被遷移到了新的 Node 3 節點,現在每個節點上都擁有2個分片,而不是之前的3個。 這表示每個節點的硬件資源(CPU, RAM, I/O)將被更少的分片所共享,每個分片的性能將會得到提升。

分片是一個功能完整的搜索引擎,它擁有使用一個節點上的所有資源的能力。 我們這個擁有6個分片(3個主分片和3個副本分片)的索引可以最大擴容到6個節點,每個節點上存在一個分片,並且每個分片擁有所在節點的全部資源。

但是如果我們想要擴容超過6個節點怎麼辦呢?

主分片的數目在索引創建時 就已經確定了下來。實際上,這個數目定義了這個索引能夠 存儲 的最大數據量。(實際大小取決於你的數據、硬件和使用場景。) 但是,讀操作——搜索和返回數據——可以同時被主分片  副本分片所處理,所以當你擁有越多的副本分片時,也將擁有越高的吞吐量。

在運行中的集羣上是可以動態調整副本分片數目的 ,我們可以按需伸縮集羣。讓我們把副本數從默認的 1增加到 2 :

PUT /blogs/_settings
{
   "number_of_replicas" : 2
}

圖 5 “將參數 number_of_replicas 調大到 2”所示, blogs 索引現在擁有9個分片:3個主分片和6個副本分片。 這意味着我們可以將集羣擴容到9個節點,每個節點上一個分片。相比原來3個節點時,集羣搜索性能可以提升 3 倍。

將參數 number_of_replicas 調大到 2

擁有2份副本分片3個節點的集羣

 

當然,如果只是在相同節點數目的集羣上增加更多的副本分片並不能提高性能,因爲每個分片從節點上獲得的資源會變少。 你需要增加更多的硬件資源來提升吞吐量。

但是更多的副本分片數提高了數據冗餘量:按照上面的節點配置,我們可以在失去2個節點的情況下不丟失任何數據。

六、節點故障

們之前說過 Elasticsearch 可以應對節點故障,接下來讓我們嘗試下這個功能。 如果我們關閉第一個節點,這時集羣的狀態爲圖 6 “關閉了一個節點後的集羣”

關閉了一個節點後的集羣

我們關閉的節點是一個主節點。而集羣必須擁有一個主節點來保證正常工作,所以發生的第一件事情就是選舉一個新的主節點: Node 2 。

在我們關閉 Node 1 的同時也失去了主分片 1 和 2 ,並且在缺失主分片的時候索引也不能正常工作。 如果此時來檢查集羣的狀況,我們看到的狀態將會爲 red :不是所有主分片都在正常工作。

幸運的是,在其它節點上存在着這兩個主分片的完整副本, 所以新的主節點立即將這些分片在 Node 2 和 Node 3 上對應的副本分片提升爲主分片, 此時集羣的狀態將會爲 yellow 。 這個提升主分片的過程是瞬間發生的,如同按下一個開關一般。

爲什麼我們集羣狀態是 yellow 而不是 green 呢? 雖然我們擁有所有的三個主分片,但是同時設置了每個主分片需要對應2份副本分片,而此時只存在一份副本分片。 所以集羣不能爲 green 的狀態,不過我們不必過於擔心:如果我們同樣關閉了 Node 2 ,我們的程序 依然 可以保持在不丟任何數據的情況下運行,因爲 Node 3 爲每一個分片都保留着一份副本。

如果我們重新啓動 Node 1 ,集羣可以將缺失的副本分片再次進行分配,那麼集羣的狀態也將如圖 5 “將參數 number_of_replicas 調大到 2”所示。 如果 Node 1 依然擁有着之前的分片,它將嘗試去重用它們,同時僅從主分片複製發生了修改的數據文件。

 

 

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