概要
本篇開始介紹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機器上,我們執行以下操作:
- 生成公鑰檔案,命令:
ssh-keygen -t rsa
一直輸入回車,不要設定密碼預設會將公鑰放在/root/.ssh目錄下生成id_rsa.pub和id_rsa兩個檔案
- 拷貝公鑰檔案
cp id_rsa.pub authorized_keys
- 將公鑰檔案拷貝到另外三臺機器
ssh-copy-id -i elasticsearch02
ssh-copy-id -i elasticsearch03
ssh-copy-id -i elasticsearch03
拷貝完成後,可以在目標機器上/root/.ssh/
目錄下看到多了一個authorized_keys檔案。
- 嘗試免密登入,在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資訊。
叢集發現的一般步驟如下:
- 節點配置network.host繫結內網地址,配置各自的node.name資訊,cluster.name設定為相同的值。
- discovery.zen.ping.unicast.hosts配置了幾個gossip路由的node。
- 所有node都可以傳送ping訊息到路由node,再從路由node獲取cluster state回來。
- 所有node執行master選舉。
- 所有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候選節點當機了,叢集就無法正常運作了。
叢集故障探查
有兩種叢集故障探查機制
- master主動對叢集中所有的其他node發起ping命令,判斷它們是否是存活著的。
- 每個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。更新的步驟如下:
- master node收到更新事件,如shard移動,可能會有多條事件,但master node一次只處理一個叢集狀態的更新事件。
- master node將事件更新到本地,併發布publish message到叢集所有的node上。
- node接收publish message後,對這個message返回ack響應,但是不會立即更新。
- 如果master沒有在指定的時間內(discovery.zen.commit_timeout配置項,預設是30s),從至少N個節點(discovery.zen.minimum_master_nodes配置項)獲取ack響應,那麼這次cluster state change事件就會被reject,最終不會被提交。
- 如果在指定時間內,指定數量的node都返回了ack訊息,那麼cluster state就會被commit,然後master node把 commit message傳送給所有的node。所有的node接收到那個commit message之後,接著才會將之前接收到的叢集狀態應用到自己本地的狀態副本中去。
- 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架構社群微信群共同探討技術