1. 程式人生 > >(十四)Elasticsearch叢集配置

(十四)Elasticsearch叢集配置

本文作者:羅海鵬,叩丁狼高階講師。原創文章,轉載請註明出處。

前言

  在我們es系列文章開篇介紹中,已經提到,elasticsearch是天生支援叢集的,他不需要依賴其他的服務發現和註冊的元件,如zookeeper這些,因為他內建了一個名字叫ZenDiscovery的模組,是elasticsearch自己實現的一套用於節點發現和選主等功能的元件,所以elasticsearch做起叢集來非常簡單,不需要太多額外的配置和安裝額外的第三方元件。

資料分片

  我們在前面的篇章中介紹過elasticsearch的一些重要的基本概念了,但是為了循序漸進的學習elasticsearch,我們並沒有把所有概念都一次性列出來,而是在學習的過程中不斷的補充,那現在我們需要學習elasticsearch的叢集了,就需要補充一個基本概念,叫做“分片(shard)”,分片在叢集中起到了非常關鍵的作用,那接下來,我們來看看分片是什麼。
分片的概念和作用


  分片是一個底層的工作單元 ,它僅儲存了全部資料中的一部分,一個分片是一個 Lucene 的例項,它本身就是一個完整的搜尋引擎,我們的文件被儲存和索引到分片內。
  每個分片又有一個副本分片,副本分片就是主分片的copy,對於分散式搜尋引擎來說, 分片及副本的分配將是高可用及快速搜尋響應的設計核心.主分片與副本都能處理查詢請求,它們的唯一區別在於只有主分片才能處理更新請求,這就有點像我們常見的“主從”的概念了。
  Elasticsearch 是利用分片將資料分發到叢集內各處的。分片是資料的容器,文件儲存在分片內,分片又被分配到叢集內的各個節點裡。當你的叢集規模擴大或者縮小時, Elasticsearch 會自動的在各節點中遷移分片,使得資料仍然均勻分佈在叢集裡。所以叢集和分片關係非常密切,學習叢集之前,需要了解分片的概念和作用。

ES叢集節點型別

  通過前面對elasticsearch的基本概念瞭解到,在一個elasticsearch叢集(cluster)中,有多個節點(node),並且這些節點有不同的型別:我們部署一個elasticsearch叢集常用的節點型別有:主節點,資料節點,候選主節點,客戶端節點。
這些節點的型別是通過在elasticsearch主配置檔案path/to/config/elasticsearch.yml檔案指定的,配置屬性如下:

node.master: true/false #該節點有機會成為master節點
node.data: true/false #該節點可以儲存資料

 &emsp通過以上兩行配置的組合,我們可以指定出elasticsearch的節點型別。
每種節點的作用如下:

1、主節點:

  主節點負責建立索引、刪除索引、分配分片、追蹤叢集中的節點狀態等工作。Elasticsearch中的主節點的工作量相對較輕,使用者的請求可以發往叢集中任何一個節點,由該節點負責分發和返回結果,而不需要經過主節點轉發。而主節點是由候選主節點通過ZenDiscovery機制選舉出來的,所以要想成為主節點,首先要先成為候選主節點。

2、候選主節點

  在elasticsearch叢集初始化或者主節點宕機的情況下,由候選主節點中選舉其中一個作為主節點。指定候選主節點的配置為:node.master: true
  但是在elasticsearch叢集中,會有偶爾出現這樣的一種現象,就是當主節點負載壓力過大,或者集中環境中的網路問題,導致其他節點與主節點通訊的時候,主節點沒來的及響應,這樣的話,某些節點就認為主節點宕機,重新選擇新的主節點,這樣的話整個叢集的工作就有問題了,比如我們叢集中有10個節點,其中7個候選主節點,1個候選主節點成為了主節點,這種情況是正常的情況。但是如果現在出現了我們上面所說的主節點響應不及時,導致其他某些節點認為主節點宕機而重選主節點,那就有問題了,這剩下的6個候選主節點可能有3個候選主節點去重選主節點,最後叢集中就出現了兩個主節點的情況,這種情況官方成為“腦裂現象”
如果避免這種問題呢?主要從以下幾個方面來避免:
(1)儘量不要讓候選主節點同時作為資料節點,因為資料節點是需要承擔儲存和搜尋的工作的,壓力會很大。所以如果該節點同時作為候選主節點和資料節點,那麼一旦選上它作為主節點了,這時主節點的工作壓力將會非常大,出現腦裂現象的概率就增加了。
(2)配置主節點的響應時間,在預設情況下,主節點3秒沒有響應,其他節點就認為主節點宕機了,那我們可以把該時間設定的長一點,該配置是:discovery.zen.ping_timeout: 3
(3)配置候選主節點最小數量,從腦裂現象出現的原因中,我們看到了,如果叢集中有部分候選主節點重新選擇主節點,那叢集中的候選主節點就會被分成兩部分,導致叢集的可用節點個數和實際的節點個數不一致,那這樣的話,我們就可用通過配置的方式,指定如果候選主節點個數達到某個值時,才能進行主節點選舉,而該配置屬性如下:discovery.zen.minimum_master_nodes,該屬性預設值是1,官方的推薦值是(N/2)+1,其中N是候選主節點的數量,那這樣的話,比如我們叢集有7個候選主節點,那麼通過官方推薦值,我們應該設定為4,這樣的話,至少有4個候選主節點都認為需要重選主節點的情況下才進行選舉。

3、資料節點

  資料節點負責資料的儲存和相關具體操作,比如CRUD、搜尋、聚合。所以,資料節點對機器配置要求比較高,首先需要有足夠的磁碟空間來儲存資料,其次資料操作對系統CPU、Memory和IO的效能消耗都很大。通常隨著叢集的擴大,需要增加更多的資料節點來提高可用性。指定資料節點的配置:node.data: true
elasticsearch是允許一個節點既做候選主節點也做資料節點的,但是資料節點的負載較重,所以需要考慮將二者分離開,設定專用的候選主節點和資料節點,避免因資料節點負載重導致主節點不響應。

4、客戶端節點

  按照官方的介紹,客戶端節點就是既不做候選主節點也不做資料節點的節點,只負責請求的分發、彙總等等,但是這樣的工作,其實任何一個節點都可以完成,因為在elasticsearch中一個叢集內的節點都可以執行任何請求,其會負責將請求轉發給對應的節點進行處理。所以單獨增加這樣的節點更多是為了負載均衡。指定該節點的配置為:

node.master: false 
node.data: false 

叩丁狼教育.png

叩丁狼教育.png

叢集配置

接下來,我們做一個叢集測試一下,我這裡使用4個節點做測試,分別為:

es1   192.168.85.133:9300
es2   192,168.85.133:9500
es3   192.168.85.135:9300
es4   192.168.85.135:9500

1、es1 既是候選主節點也是資料節點,elasticsearch.yml配置如下:

cluster.name: elasticsearch #叢集的名稱,同一個叢集該值必須設定成相同的
node.name: es1 #該節點的名字
node.master: true #該節點有機會成為master節點
node.data: true #該節點可以儲存資料
network.bind_host: 0.0.0.0 #設定繫結的IP地址,可以是IPV4或者IPV6
network.publish_host: 192.168.85.133 #設定其他節點與該節點互動的IP地址
network.host: 192.168.85.133 #該引數用於同時設定bind_host和publish_host
transport.tcp.port: 9300 #設定節點之間互動的埠號
transport.tcp.compress: true #設定是否壓縮tcp上互動傳輸的資料
http.port: 9200 #設定對外服務的http埠號
http.max_content_length: 100mb #設定http內容的最大大小
http.enabled: true #是否開啟http服務對外提供服務
discovery.zen.minimum_master_nodes: 2 #設定這個引數來保證叢集中的節點可以知道其它N個有master資格的節點。官方推薦(N/2)+1
discovery.zen.ping_timeout: 120s #設定叢集中自動發現其他節點時ping連線的超時時間
discovery.zen.ping.unicast.hosts: ["192.168.85.133:9300","192.168.85.133:9500","192.168.85.135:9300"] #設定叢集中的Master節點的初始列表,可以通過這些節點來自動發現其他新加入叢集的節點
http.cors.enabled: true  #跨域連線相關設定
http.cors.allow-origin: "*"  #跨域連線相關設定  

2、es2 既是候選主節點也是資料節點,elasticsearch.yml配置如下:

cluster.name: elasticsearch #叢集的名稱,同一個叢集該值必須設定成相同的
node.name: es2 #該節點的名字
node.master: true #該節點有機會成為master節點
node.data: true #該節點可以儲存資料
network.bind_host: 0.0.0.0 #設定繫結的IP地址,可以是IPV4或者IPV6
network.publish_host: 192.168.85.133 #設定其他節點與該節點互動的IP地址
network.host: 192.168.85.133 #該引數用於同時設定bind_host和publish_host
transport.tcp.port: 9500 #設定節點之間互動的埠號
transport.tcp.compress: true #設定是否壓縮tcp上互動傳輸的資料
http.port: 9400 #設定對外服務的http埠號
http.max_content_length: 100mb #設定http內容的最大大小
http.enabled: true #是否開啟http服務對外提供服務
discovery.zen.minimum_master_nodes: 2 #設定這個引數來保證叢集中的節點可以知道其它N個有master資格的節點。官方推薦(N/2)+1
discovery.zen.ping_timeout: 120s #設定叢集中自動發現其他節點時ping連線的超時時間
discovery.zen.ping.unicast.hosts: ["192.168.85.133:9300","192.168.85.133:9500","192.168.85.135:9300"] #設定叢集中的Master節點的初始列表,可以通過這些節點來自動發現其他新加入叢集的節點
http.cors.enabled: true  #跨域連線相關設定
http.cors.allow-origin: "*"  #跨域連線相關設定  

3、es3 是候選主節點,elasticsearch.yml配置如下:

cluster.name: elasticsearch #叢集的名稱,同一個叢集該值必須設定成相同的
node.name: es3 #該節點的名字
node.master: true #該節點有機會成為master節點
node.data: false #該節點可以儲存資料
network.bind_host: 0.0.0.0 #設定繫結的IP地址,可以是IPV4或者IPV6
network.publish_host: 192.168.85.135 #設定其他節點與該節點互動的IP地址
network.host: 192.168.85.135 #該引數用於同時設定bind_host和publish_host
transport.tcp.port: 9300 #設定節點之間互動的埠號
transport.tcp.compress: true #設定是否壓縮tcp上互動傳輸的資料
http.port: 9200 #設定對外服務的http埠號
http.max_content_length: 100mb #設定http內容的最大大小
http.enabled: true #是否開啟http服務對外提供服務
discovery.zen.minimum_master_nodes: 2 #設定這個引數來保證叢集中的節點可以知道其它N個有master資格的節點。官方推薦(N/2)+1
discovery.zen.ping_timeout: 120s #設定叢集中自動發現其他節點時ping連線的超時時間
discovery.zen.ping.unicast.hosts: ["192.168.85.133:9300","192.168.85.133:9500","192.168.85.135:9300"] #設定叢集中的Master節點的初始列表,可以通過這些節點來自動發現其他新加入叢集的節點
http.cors.enabled: true  #跨域連線相關設定
http.cors.allow-origin: "*"  #跨域連線相關設定  

4、es4 是資料節點,elasticsearch.yml配置如下:

cluster.name: elasticsearch #叢集的名稱,同一個叢集該值必須設定成相同的
node.name: es4 #該節點的名字
node.master: false #該節點有機會成為master節點
node.data: true #該節點可以儲存資料
network.bind_host: 0.0.0.0 #設定繫結的IP地址,可以是IPV4或者IPV6
network.publish_host: 192.168.85.135 #設定其他節點與該節點互動的IP地址
network.host: 192.168.85.135 #該引數用於同時設定bind_host和publish_host
transport.tcp.port: 9500 #設定節點之間互動的埠號
transport.tcp.compress: true #設定是否壓縮tcp上互動傳輸的資料
http.port: 9400 #設定對外服務的http埠號
http.max_content_length: 100mb #設定http內容的最大大小
http.enabled: true #是否開啟http服務對外提供服務
discovery.zen.minimum_master_nodes: 2 #設定這個引數來保證叢集中的節點可以知道其它N個有master資格的節點。官方推薦(N/2)+1
discovery.zen.ping_timeout: 120s #設定叢集中自動發現其他節點時ping連線的超時時間
discovery.zen.ping.unicast.hosts: ["192.168.85.133:9300","192.168.85.133:9500","192.168.85.135:9300"] #設定叢集中的Master節點的初始列表,可以通過這些節點來自動發現其他新加入叢集的節點
http.cors.enabled: true  #跨域連線相關設定
http.cors.allow-origin: "*"  #跨域連線相關設定  

  以上配置就是我們叢集中4個elasticsearch節點的配置,我們沒有兩個既是候選主節點也是資料節點,一個候選主節點,一個數據節點,沒有配置客戶端節點,因為客戶端節點僅起到負載均衡的作用。

驗證群狀態

檢視叢集狀態的REST API
我們逐一的把叢集中的節點啟動起來,然後使用REST API檢視叢集狀態,訪問叢集中任意一個節點即可:
GET ip:port/_cluster/health
響應的結果:

{
  "cluster_name" : "elasticsearch",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 4,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 46,
  "active_shards" : 92,
  "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.0
}

我們來看看返回結果中的幾個關鍵的屬性:

  • 叢集狀態有3種(status):
    red,表示有主分片沒有分配,某些資料不可用。
    yellow,表示主分片都已分配,資料都可用,但是有複製分片沒有分配。
    green,表示主分片和複製分片都已分配,一切正常。
    那麼通過以上返回的結果中的status屬性,我們可以知道,當前的elasticsearch叢集是正常的。
  • number_of_nodes屬性說明我們叢集中有4個節點。
  • number_of_data_nodes說明我們叢集中有3個為資料節點,所有資料分片儲存在這3個數據節點中。
  • active_primary_shards屬性說明主分片有46個(我們有10個索引,其中9個索引有5個主分片,1個索引有1個主分片,合計46個主分片)
  • active_shards屬性說明所有分片(主分片 + 副本分片)總共是92個

使用head外掛管理ES叢集
  我們在之前安裝了es-head外掛的時候提到,es-head外掛可以管理我們elasticsearch叢集的,那現在我們就使用之前安裝好的es-head外掛來看看elasticsearch叢集如果做到圖形化介面的管理。
開啟首頁我們可以看到以下介面:

叩丁狼教育.png

叩丁狼教育.png


  連線任意一個節點看到的結果都是一樣的,這個就驗證了我們上面提到的概念:使用者的請求可以發往叢集中任何一個節點,由該節點負責請求分發和返回結果。

 

  • 在該介面中,是以表格的形式展示資料的,縱向的是叢集中的索引,橫向的是叢集中的節點。
  • 橫向有4行,分別是4個我們自己命名的節點,其中標記了es1是星號,代表它為主節點。
  • 然後我們可以看到,每個單元格中都有一些綠色的小方塊,小方塊中標有數字,這些綠色小方塊就代表分片,其中邊框加粗的是主分片,沒加粗的是副本分片。
  • 我們在建立索引時,如果沒有指定分片的數量,那麼預設是5個,再加上每個分片都有一個副本,所以加起來就有10個綠色小方塊了。
  • 每個綠色小方塊上都有0-4的數字,分別代表0-4號分片,和對應的0-4號分片的副本分片,我們點選綠色小方塊,會彈出一個視窗,列出該分片的一些資訊,其中有條資訊是“primary”,如果為true,就代表主分片,發false就代表副本分片。
  • 其中es3節點是沒有給它分配分片的,那是因為當時我們給該節點設定的是候選主節點,不是資料節點,所以他不承擔資料儲存的工作。
  • 這10個分片(包含主分片和副本分片)被elasticsearch分配到各個資料節點中,並且根據我們上面對分片概念的瞭解,主分片和副本分片都可以接收資料查詢請求,但是隻有主分片才能接收資料修改請求,副本分片的資料是從主分片同步過來的。
    測試資料
      最後,我們從使用者的角度上來看看,向叢集中各個節點發送一個查詢請求,測試資料的一致性。
    我們先往叢集中新增一條資料,以store索引作為測試,向任意一個節點發送一個新增文件的請求:
PUT /store/employee/3
{
    "name":"王五",
    "age":28,
    "about":"我叫王五,但不是隔壁老王",
    "interests":["code","music"]
}

看到以下返回結果提示新增成功:

 

叩丁狼教育.png

叩丁狼教育.png

 

  但這裡有一個問題,就是該文件會被儲存到哪一個主分片中呢?首先這肯定不會是隨機的,否則將來要獲取文件的時候我們就不知道從何處尋找了。實際上,這個過程是根據下面這個公式決定的:

shard = hash(routing) % number_of_primary_shards

routing 是一個可變值,預設是文件的 _id ,也可以設定成一個自定義的值。 routing 通過 hash 函式生成一個數字,然後這個數字再除以 number_of_primary_shards (主分片的數量)後得到 餘數 。這個分佈在 0 到 number_of_primary_shards-1 之間的餘數,就是我們所尋求的文件所在分片的位置。

這就順便解釋了為什麼我們要在建立索引的時候就確定好主分片的數量,並且永遠不會改變這個數量,因為如果數量變化了,那麼所有之前路由的值都會無效,文件也再也找不到了。

那接下來我們看看每個節點是否可以查詢到該資料:

 

叩丁狼教育.png

叩丁狼教育.png

叩丁狼教育.png

叩丁狼教育.png

叩丁狼教育.png

叩丁狼教育.png

 

叩丁狼教育.png

叩丁狼教育.png

 

  這4個節點都是可以查詢到剛剛我們新增的文件id為3的資料,叢集正常運作。在我們整個叢集配置的過程中,需要我們配置的東西很少,所以elasticsearch真的可以很輕鬆的完成一個規模超大的叢集,並且在該叢集中儲存海量的資料。

想獲取更多技術乾貨,請前往叩丁狼官網:http://www.wolfcode.cn/all_article.html