Elasticsearch系列---生產叢集部署(上)

清茶豆奶發表於2020-05-30

概要

本篇開始介紹Elasticsearch生產叢集的搭建及相關引數的配置。

ES叢集的硬體特性

我們從開始程式設計就接觸過各種各樣的元件,而每種功能的元件,對硬體要求的特性都不太相同,有的需要很強的CPU計算能力,有的對記憶體需求量大,有的對網路卡要求高等待,下面我們討論一下ES叢集對幾種硬體的特性需求。

CPU

ES叢集對CPU的要求相對低一些,畢竟純計算的比重要小一些,選用主流的CPU,2核到8核的都可以。

如果有兩種CPU可以挑選,一種是主頻高但核數少的CPU,另一種是主頻一般核數多的CPU,肯定選後一種,因為多核的CPU可以提供更多的併發處理能力,遠比單核高效能帶來的效益要高。

記憶體

ES叢集對記憶體的要求很高,部署ES叢集時,要把大部分資源投入到記憶體當中。記憶體分配主要有兩部分,JVM heap記憶體(堆記憶體)和OS Cache記憶體。

JVM heap記憶體用得不多,主要是OS Cache,我們知道,ES建立的倒排索引,正排索引,過濾器快取,都是優先放在記憶體當中的,OS Cache的大小直接決定搜尋的效能,如果OS Cache不夠,ES搜尋等操作只有被迫讀硬碟,延時就會從毫秒級升到秒級。

OS Cache具體在多大才算夠,取決於資料量,如果是百萬級別的資料,16GB左右應該可以接受,如果是億級,一般單節點都是64GB記憶體。生產環境最低要求記憶體應不低於8GB。

硬碟

硬碟成本本身比較便宜,能用SSD就用SSD,訪問速度肯定比機械硬碟快,預估好資料量後就儘可能多規劃一些容量。

另外儘量使用本地儲存,網路儲存還依賴於網路傳輸,這個容易造成一些延遲。

網路

對ES叢集這種分散式系統來說,快速並且可靠的網路還是比較重要的,shard的分配和rebalance都需要佔用大量的頻寬,叢集最好部署在同一個區域網內,異地容災等跨資料中心的部署方案,要考慮到網路故障帶來的影響。

JVM選擇

使用ES官網推薦的JDK版本,服務端和客戶端儘量使用同一個版本的JDK。

涉及到ES服務端的JVM調優設定,保持原樣不要輕易改動,畢竟ES已經花了大量人力物力驗證過的,隨意調整jvm引數可能適得其反。

容量規劃

規劃叢集裡,要規劃好投入幾臺伺服器,資料量上限是多少,業務模型資料讀寫的比例是多少,歷史資料的遷移方案等,一般來說,百萬到10億內的資料量,使用ES叢集還是能夠支撐下來的,ES節點數建議不要超過100個。

舉個例子:資料量10億以內,部署5臺伺服器,8核64GB記憶體,是能夠支撐的。

生產案例模擬

Linux作業系統搭建

我們使用Linux虛擬機器來演示一個生產ES叢集的搭建。我們建立4臺虛擬機器,每臺2核CPU,4GB記憶體,作業系統為CentOS 7 64bit。

虛擬機器我用的是VMware workstation,有用virtual box也行,CentOS 7、JDK的安裝不贅述。記得把CentOS的防火牆關了。

修改每臺機器的hostname資訊,命令
vi /etc/hostname,修改檔案,儲存即可,建議修改成elasticsearch01,elasticsearch02,elasticsearch03,elasticsearch04。

假定我們4臺虛擬機器的域名和IP是這樣分配的:

192.168.17.138 elasticsearch01
192.168.17.137 elasticsearch02
192.168.17.132 elasticsearch03
192.168.17.139 elasticsearch04

把這段配置放在 /etc/hosts檔案末尾,4臺機器做相同的配置。

這4臺機器之間,可以配置免密登入,如在elasticsearch01機器上,我們執行以下操作:

  1. 生成公鑰檔案,命令:
ssh-keygen -t rsa

一直輸入回車,不要設定密碼預設會將公鑰放在/root/.ssh目錄下生成id_rsa.pub和id_rsa兩個檔案

  1. 拷貝公鑰檔案
cp id_rsa.pub authorized_keys
  1. 將公鑰檔案拷貝到另外三臺機器
ssh-copy-id -i elasticsearch02
ssh-copy-id -i elasticsearch03
ssh-copy-id -i elasticsearch03

拷貝完成後,可以在目標機器上/root/.ssh/目錄下看到多了一個authorized_keys檔案。

  1. 嘗試免密登入,在elasticsearch01機器上輸入ssh elasticsearch02,如果不需要輸入密碼就能登入到elasticsearch02,說明配置成功,其他機器類似。

這4臺機器也可以相互做ssh免密設定。

這裡補充一點免密登入的方向性問題,上面的案例是在elasticsearch01機器生成的公鑰,並且傳送給了elasticsearch02等三臺機器,那麼我從elasticsearch01跳到elasticsearch02是不需要密碼的,反過來從elasticsearch02登入到elasticsearch01,還是需要密碼的。

最後補充幾個常用檢查命令:

  • 檢查NetManager的狀態:systemctl status NetworkManager.service
  • 檢查NetManager管理的網路介面:nmcli dev status
  • 檢查NetManager管理的網路連線:nmcli connection show

Elasticsearch服務端

這裡選用的JDK版本為1.8.0_211,Elasticsearch版本為6.3.1,自行安裝不贅述。

ES解壓後的目錄結構:

# 用 "tree -L 1" 命令得到的樹狀結構
.
├── bin
├── config
├── lib
├── LICENSE.txt
├── logs
├── modules
├── NOTICE.txt
├── plugins
└── README.textile
  • bin:存放es的一些可執行指令碼,比如用於啟動程式的elasticsearch命令,以及用於安裝外掛的elasticsearch-plugin外掛
  • config:用於存放es的配置檔案,比如elasticsearch.yml
  • logs:用於存放es的日誌檔案
  • plugins:用於存放es的外掛
  • data:用於存放es的資料檔案的預設目錄,就是每個索引的shard的資料檔案,一般會另外指定一個目錄。

Elasticsearch引數設定

在config目錄下的檔案,包含了ES的基本配置資訊:

.
├── elasticsearch.yml
├── jvm.options
├── log4j2.properties
├── role_mapping.yml
├── roles.yml
├── users
└── users_roles

預設引數

Elasticsearch的配置項比較豐富並且預設配置已經非常優秀了,基本上我們需要改動的是跟伺服器環境相關的配置,如IP地址,叢集名稱,資料儲存位置,日誌儲存位置等外圍引數,涉及到內部機制及JVM引數的,一般不干預,不恰當的JVM引數調整反而會導致叢集出現效能故障,如果沒有充足的理由或資料驗證結果,不要輕易嘗試修改。

叢集和節點名稱

在elasticsearch.yml檔案裡這項配置表示叢集名稱,配置項預設是註釋掉的,叢集名稱預設為elasticsearch。

#cluster.name: my-application

這個配置項強烈建議開啟,用專案約定的命名規範進行重新命名,並且將研發環境、測試環境、STG準生產環境、生產環境分別命名,如elasticsearch_music_app_dev表示研發環境,elasticsearch_music_app_sit表示測試環境,elasticsearch_music_app_pro表示生產環境等。避免開發測試環境連錯環境,無意中加入叢集導致資料問題。

cluster.name: elasticsearch_music_app_pro

節點名稱的配置項

#node.name: node-1

預設也是註釋掉的,ES啟動時會分配一個隨機的名稱,建議還是自行分配一個名稱,這樣容易記住是哪臺機器,如

node.name: es_node_001_data

檔案路徑

涉及到檔案路徑的幾個引數,主要有資料、日誌、外掛等,預設這幾個地址都是在Elasticsearch安裝的根目錄下,但Elasticsearch升級時,有些目錄可能會有影響,安全起見,可以單獨設定目錄。

#
# ----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#
#path.data: /path/to/data
#
# Path to log files:
#
#path.logs: /path/to/logs
#

例如我們可以在/var目錄下建立相應的資料夾,並且賦予相應的讀寫許可權,如:

path.data: /var/es/data
path.logs: /var/es/logs

日誌檔案配置

log4j2.properties檔案,ES日誌框架選用的是log4j2,也就是log4j的進化版本,對Java技術棧熟悉的童鞋,看到這個配置檔案會非常熟悉,預設的日誌輸入配置、格式均能滿足日常的故障定位和分析,也不需要什麼改動。

預設是一天生成一個日期檔案,如果ES承載的資料量特別大,可以調整日誌檔案產生頻率和每個日誌檔案的大小,以及ES最多儲存日誌的大小、數量。

Elasticsearch叢集發現機制

配置引數

Zen Discovery是Elasticsearch叢集發現機制的預設實現,底層通訊依賴transport元件,我們完成Elasticsearch叢集的配置主要有下面幾個引數:

  • cluster.name 指定叢集的名稱。
  • node.name 節點名稱。
  • network.host 節點繫結的IP。
  • node.master 可選值為true/false,決定該節點型別為master eligible或data node。
  • discovery.zen.ping.unicast.hosts gossip路由服務的IP地址,即叢集發現協議通訊的公共節點,可以寫多個,有節點啟動時會向裡面的IP傳送訊息,獲取叢集其他節點的資訊,最後加入叢集。

Elasticsearch叢集是點對點(P2P)的分散式系統架構,資料索引、搜尋操作是node之間直接通訊的,沒有中心式的master節點,但Elasticsearch叢集內的節點也分成master node和data node兩種角色。

正常情況下,Elasticsearch叢集只有一個master節點,它負責維護整個叢集的狀態資訊,叢集的後設資料資訊,有新的node加入或叢集內node當機下線時,重新分配shard,並同步node的狀態資訊給所有的node節點,這樣所有的node節點都有一份完整的cluster state資訊。

叢集發現的一般步驟如下:

  1. 節點配置network.host繫結內網地址,配置各自的node.name資訊,cluster.name設定為相同的值。
  2. discovery.zen.ping.unicast.hosts配置了幾個gossip路由的node。
  3. 所有node都可以傳送ping訊息到路由node,再從路由node獲取cluster state回來。
  4. 所有node執行master選舉。
  5. 所有node都會跟master進行通訊,然後加入master的叢集。

master選舉

node.master設定為true的,將成為master eligible node,也叫master候選節點,只有master eligible node才能被選舉成master node。如果是個小叢集,那麼所有節點都可以是master eligible node,10個節點以上的叢集,可以考慮拆分master node和data node,一般建議master eligible node給3個即可。

master選舉過程是自動完成的,有幾個引數可以影響選舉的過程:

  • discovery.zen.ping_timeout: 選舉超時時間,預設3秒,網路狀況不好時可以增加超時時間。

  • discovery.zen.join_timeout: 有新的node加入叢集時,會傳送一個join request到master node,同樣因為網路原因可以調大,如果一次超時,預設最多重試20次。

  • discovery.zen.master_election.ignore_non_master_pings:如果master node意外當機了,叢集進行重新選舉,如果此值為true,那麼只有master eligible node才有資格被選為master。

  • discovery.zen.minimum_master_nodes: 新選舉master時,要求必須有多少個 master eligible node去連線那個新選舉的master。而且還用於設定一個叢集中必須擁有的master eligible node。如果這些要求沒有被滿足,那麼master node就會被停止,然後會重新選舉一個新的master。這個引數必須設定為我們的master eligible node的quorum數量。一般避免說只有兩個master eligible node,因為2的quorum還是2。如果在那個情況下,任何一個master候選節點當機了,叢集就無法正常運作了。

叢集故障探查

有兩種叢集故障探查機制

  1. master主動對叢集中所有的其他node發起ping命令,判斷它們是否是存活著的。
  2. 每個node向master node傳送ping請求,判斷master node是否存活,否則就會發起一個選舉過程。

有下面三個引數用來配置叢集故障的探查過程:

  • ping_interval:ping一次node的間隔時間,預設是1s
  • ping_timeout:每次ping的timeout等待時長,預設是30s
  • ping_retries:對node的ping請求失敗了,重試次數,預設3次。

叢集狀態更新

master node是叢集中唯一可以對cluster state進行更新的node。更新的步驟如下:

  1. master node收到更新事件,如shard移動,可能會有多條事件,但master node一次只處理一個叢集狀態的更新事件。
  2. master node將事件更新到本地,併發布publish message到叢集所有的node上。
  3. node接收publish message後,對這個message返回ack響應,但是不會立即更新。
  4. 如果master沒有在指定的時間內(discovery.zen.commit_timeout配置項,預設是30s),從至少N個節點(discovery.zen.minimum_master_nodes配置項)獲取ack響應,那麼這次cluster state change事件就會被reject,最終不會被提交。
  5. 如果在指定時間內,指定數量的node都返回了ack訊息,那麼cluster state就會被commit,然後master node把 commit message傳送給所有的node。所有的node接收到那個commit message之後,接著才會將之前接收到的叢集狀態應用到自己本地的狀態副本中去。
  6. master會等待所有node的commit message 的ack訊息,在一個等待超時時長內,如果接收到了響應,表示狀態更新成功,master node繼續處理記憶體queue中儲存的下一個更新事件。

discovery.zen.publish_timeout預設是30s,這個超時等待時長是從plublish cluster state開始計算的。

我們可以參照此圖:

master node當機問題

Elasticsearch叢集中,master node扮演著非常重要的角色,如果master node當機了,那豈不是群龍無首了?雖然有master選舉,但這個也是要時間的,沒有master node那段空檔期叢集該怎麼辦?

說了一半,基本上是完了,但我們也可以設定,群龍無首時哪些操作可以做,哪些操作不能做。

discovery.zen.no_master_block配置項可以控制在群龍無首時的策略:

  • all: 一旦master當機,那麼所有的操作都會被拒絕。
  • write:預設的選項,所有寫操作都會被拒絕,但是讀操作是被允許的。

split-brain(腦分裂問題)

在Elasticsearch叢集中,master node非常重要,並且只有一個,相當於整個叢集的大腦,控制將整個叢集狀態的更新,如果Elasticsearch叢集節點之間出現區域性的網路中斷,比如10個節點的Elasticsearch叢集,4臺node部署在機房A區,6臺node部署在機房B區,如果A區與B區的交換機故障,導致兩個區隔離開來了,那麼沒有master node的那個區,會觸發master選舉,如果選舉了新的master,那麼整個叢集就會出現兩個master node,這種現象叫做腦分裂。

這樣現象很嚴重,會破壞叢集的資料,該如何避免呢?

回到我們前面提到的discovery.zen.minimum_master_nodes引數,這個值的正確設定,可以避免上述的腦分裂問題。

discovery.zen.minimum_master_nodes參數列示至少需要多少個master eligible node,才可以成功地選舉出master,否則不進行選舉。

足夠的master eligible node計算公式:

quorum = master_eligible_nodes / 2 + 1

如上圖我們10個node的叢集,如果全部是master eligible node,那麼quorum = 10/2 + 1 = 6。

如果我們有3個master eligible node,7個data node,那麼quorum = 3/2 + 1 = 2。

如果叢集只有2個節點,並且全是master eligible node,那麼quorum = 2/2 + 1 = 2,問題就來了,如果隨便一個node當機,在只剩下一個node情況下,無法滿足quorum的值,master永遠選舉不成功,叢集就徹底無法寫入了,所以只能設定成1,後果是隻要這兩個node之間網路斷了,就會發生腦分裂的現象。

所以一個Elasticsearch叢集至少得有3個node,全部為master eligible node的話,quorum = 3/2 + 1 = 2。如果我們設定minimum_master_nodes=2,分析一下會不會出現腦分裂的問題。

場景一:A區一個node,為master,B區兩個node,為master eligible node

A區因為只剩下一個node,無法滿足quorum的條件,此時master取消當前的master角色,且無法選舉成功。

B區兩個master eligible node,滿足quorum條件,成功選舉出master。

此時叢集還是隻有一個master,待網路故障恢復後,叢集資料正常。

場景二:A區一個node,為master eligible node,B區2個node,其中一個是master

A區只有一個master eligible node,不滿足quorum的條件,無法進行選舉。

B區原本的master存在,不需要進行選舉,並且滿quorum的條件,master角色可以保留。

此時叢集還是一個master,正常。

綜上所述:3個節點的叢集,全部為master eligible node,配置discovery.zen.minimum_master_nodes: 2,就可以避免腦裂問題的產生。

minimum_master_nodes動態修改

因為叢集是可以動態增加和下線節點的,quorum的值也會跟著改變。minimum_master_nodes引數值需要通過api隨時修改的,特別是在節點上線和下線的時候,都需要作出對應的修改。而且一旦修改過後,這個配置就會持久化儲存下來。

修改api請求如下:

PUT /_cluster/settings
{
    "persistent" : {
        "discovery.zen.minimum_master_nodes" : 2
    }
}

響應報文:

{
  "acknowledged": true,
  "persistent": {
    "discovery": {
      "zen": {
        "minimum_master_nodes": "2"
      }
    }
  },
  "transient": {}
}

也可以通過命令查詢當前的配置:

GET /_cluster/settings

響應結果如下:

{
  "persistent": {
    "discovery": {
      "zen": {
        "minimum_master_nodes": "1"
      }
    }
  },
  "transient": {}
}
留一個問題

上圖10個節點的叢集,假設全是master eligible node,按照上述的網路故障,會不會出現腦分裂現象 ?配置項minimum_master_nodes最低要配置成多少,才不會出現腦分裂的問題?

小結

本篇主要介紹了Elasticsearch叢集的部署和引數設定等知識,大部分都不需要人工干預,預設值已經是最優選,叢集發現機制和master選舉機制瞭解一下就OK。

專注Java高併發、分散式架構,更多技術乾貨分享與心得,請關注公眾號:Java架構社群
可以掃左邊二維碼新增好友,邀請你加入Java架構社群微信群共同探討技術
Java架構社群

相關文章