前言
本文的主要內容:node
分佈式介紹及cerebrogit
構建集羣github
副本與分片算法
集羣狀態與故障轉移apache
文檔分佈式存儲api
腦裂問題緩存
shard詳解bash
分佈式介紹及cerebro
ES支持集羣模式,是一個分佈式系統,其好處主要有兩個:微信
增大系統容量,如內存、磁盤,使得ES集羣能夠支持PB級的數據網絡
提升系統可用性,即便部分節點中止服務,整個集羣依然能夠正常服務
ES集羣由多個ES實例組成
不一樣集羣經過集羣名稱來區分,可經過cluster.name進行修改,名稱默認爲elasticsearch
每一個ES實例本質上是一個JVM進程,且有本身的名字,經過node.name進行修改
cerebro
cerebro 是一個ES Web管理工具,項目地址 https://github.com/lmenezes/cerebro
其配置文件爲 conf/application.conf,啓動 cerebro ,默認監聽的地址爲 0.0.0.0:9000
bin/cerebro
# 也可指定監聽ip和端口號
bin/cerebro -Dhttp.port=1234 -Dhttp.address=127.0.0.1
訪問 http://yourhost:9000 ,填寫要監控的 ES 地址:http://eshost:9200 便可進入管理界面
在cerebro管理界面中咱們能夠看到 ES節點、索引、shard的分佈、集羣參數配置等多種信息
構建集羣
若是隻有一臺機器,能夠執行下面的命令,每次指定相同的集羣名稱,不一樣的節點名稱和端口,便可在同一臺機器上啓動多個ES節點
bin/elasticsearch -Ecluster.name=my_cluster -Enode.name=node1 -Ehttp.port=9200 -d
做者的是在 virtualbox 上安裝Ubuntu虛擬機,在安裝好開發環境,正常啓動ES以後,採起復制虛擬機的作法,複製後須要修改虛擬機的UUID,作法可自行上網搜索。
做者複製了兩個,準備構建一個擁有三個ES節點的集羣。啓動虛擬機後能夠進行關閉防火牆,配置hosts以使相互之間可以經過主機名訪問,配置ssh免密訪問等操做
分別修改ES節點中的 cluster.name
爲相同名稱,node.name
爲各自的主機名,network.host
爲 0.0.0.0
,discovery.zen.ping.unicast.hosts
列表中中加入各自的 node.name
在ES主目錄下執行命令啓動ES
bin/elasticsearch
查看日誌可見集羣搭建完畢
Cluster State 集羣狀態
與ES集羣相關的數據稱爲cluster state,主要記錄以下信息:
節點信息,好比節點名稱、鏈接地址等
索引信息,好比索引名稱,配置等
其餘。。
Master Node 主節點
能夠修改cluster state的節點成爲master節點,一個集羣只能有一個
cluster state存儲在每一個節點上,master維護最新版本並同步給其餘節點
master節點是經過集羣中全部節點選舉產生的,能夠被選舉的節點成爲master-eligible(候選)節點,相關配置以下:
node.master: true
Coordinating Node
處理請求的節點即爲coordinating節點,該節點爲全部節點的默認角色,不能取消
路由請求到正確的節點處理,好比建立索引的請求到master節點
Data Node 數據節點
存儲數據的節點即爲Data節點,默認節點都是data類型,相關配置以下:
node.data: true
副本與分片
提升系統可用性
提升系統可用性可從兩個方面考慮:服務可用性和數據可用性
服務可用性:
2個節點的狀況下,容許其中1個節點中止服務
數據可用性
引入副本(Replication)解決
每一個節點上都有完備的數據
增大系統容量
如何將數據分佈於全部節點上?
引入分片(shard)解決問題
分片是ES支持PB級數據的基石
分片存儲了部分數據,能夠分佈於任意節點上
分片數在索引建立時指定且後續不容許再修改,默認爲5個
分片有主分片和副本分片之分,以實現數據的高可用
副本分片的數據由主分片同步,能夠有多個,從而提升讀取的吞吐量
分片的分佈
下圖演示的是 3 個節點的集羣中test_index的分片分佈狀況,建立時咱們指定了3個分片和副本
PUT test_index
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 3
}
}
大體是均勻分佈,實驗中若是因爲磁盤空間不足致使有分片未分配,爲了測試能夠將集羣設置 cluster.routing.allocation.disk.threshold_enabled
設置爲 false
此時增長節點是否能提升索引的數據容量?
不能,由於已經設置了分片數爲 3 ,shard的數量已經肯定,新增的節點沒法利用,
此時增長副本數可否提升索引的讀取吞吐量?
不能,由於新增的副本分片也是分佈在這 3 臺節點上,利用了一樣的資源(CPU,內存,IO等)。若是要增長吞吐量,同時還須要增長節點的數量
分片數的設定很重要,須要提早規劃好
太小會致使後續沒法經過增長節點實現水平擴容
過大會致使一個節點上分佈過多分片,形成資源浪費,同時會影響查詢性能
shard的數量的肯定:通常建議一個shard的數據量不要超過 `30G`,shard數量最小爲 2
Cluster Health 集羣健康
經過以下API能夠查看集羣健康情況,狀態status包括如下三種:
green 健康狀態,指全部主副分片都正常分配
yellow 指全部主分片都正常分配,但有副本分片未正常分配
red 有主分片未分配
GET _cluster/health
# 結果
{
"cluster_name": "elasticsearch",
"status": "yellow",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 115,
"active_shards": 115,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 111,
"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.88495575221239
}
Failover 故障轉移
集羣由 3 個節點組成,名稱分別爲 master,Hadoop2,Hadoop3, 其中 master 爲主節點,集羣狀態status爲 green
若是此時 master 所在機器宕機致使服務終止,此時集羣如何處理?
Hadoop2 和 Hadoop3 發現 master 沒法響應一段時間後會發起 master 主節點選舉,好比這裏選擇 Hadoop2 爲 master 節點。因爲此時主分片 P0 和 P2 下線,集羣狀態變爲 Red
node2 發現主分片 P0 和 P2 未分配,將 R0 和 R2 提高爲主分片,此時因爲全部主分片都正常分配,集羣狀態變爲 yellow
Hadoop2 爲 P0 和 P2 生成新的副本,集羣狀態變爲綠色
最後看看 Hadoop2 打印的日誌
文檔分佈式存儲
文檔最終會存儲在分片上。文檔選擇分片須要文檔到分片的映射算法,目的是使得文檔均勻分佈在全部分片上,以充分利用資源。
算法:
隨機選擇或者round-robin算法?不可取,由於須要維護文檔到分片的映射關係,成本巨大
根據文檔值實時計算對應的分片
文檔到分片的映射算法
ES經過以下的公式計算文檔對應的分片
shard = hash(routing) % number_of_primary_shards
hash算法保證能夠將數據均勻地分散在分片中
routing是一個關鍵參數,默認是文檔id,也能夠自行指定
number_of_primary_shards是主分片數
該算法與主分片數相關,這也是分片數一旦肯定後便不能更改的緣由
文檔建立流程
Client向node3發起建立文檔的請求
node3經過routing計算該文檔應該存儲在shard1上,查詢cluster state後確認主分片P1在node2上,而後轉發建立文檔的請求到node2
P1 接收並執行建立文檔請求後,將一樣的請求發送到副本分片R1
R1接收並執行建立文檔請求後,通知P1成功的結果
P1接收副本分片結果後,通知node3建立成功
node3返回結果到Client
文檔讀取流程
Client向node3發起獲取文檔1的請求
node3經過routing計算該文檔在shard1上,查詢cluster state後獲取shard1的主副分片列表,而後以輪詢的機制獲取一個shard,好比這裏是R1,而後轉發讀取文檔的請求到node1
R1接收並執行讀取文檔請求後,將結果返回node3
node3返回結果給client
文檔批量建立的流程
client向node3發起批量建立文檔的請求(bulk)
node3經過routing計算全部文檔對應的shard,而後按照主shard分配對應執行的操做,同時發送請求到涉及的主shard,好比這裏3個主shard都須要參與
主shard接收並執行請求後,將一樣的請求同步到對應的副本shard
副本shard執行結果後返回到主shard,主shard再返回node3
node3整合結果後返回client
文檔批量讀取的流程
client向node3發起批量獲取全部文檔的請求(mget)
node3經過routing計算全部文檔對應的shard,而後經過輪詢的機制獲取要參與shard,按照shard投建mget請求,經過發送請求到涉及shard,好比這裏有2個shard須要參與
R1,R2返回文檔結果
node3返回結果給client
腦裂問題
腦裂問題,英文爲split-brain,是分佈式系統中的經典網絡問題,以下圖所示:
3個節點組成的集羣,忽然node1的網絡和其餘兩個節點中斷
node2與node3會從新選舉master,好比node2成爲了新的master,此時會更新cluster state
node1本身組成集羣后,也更新cluster state
同一個集羣有兩個master,並且維護不一樣的cluster state,網絡恢復後沒法選擇正確的master
解決方案爲僅在可選舉master-eligible節點數大於等於quorum時才能夠進行master選舉
quorum = master-eligible節點數/2 + 1
,例如3個master-eligible節點時,quorum 爲2設定
discovery.zen.minimun_master_nodes
爲quorum
便可避免腦裂問題
倒排索引的不可變動
倒排索引一旦生成,不能更改
其好處以下:
不用考慮併發寫文件的問題,杜絕了鎖機制帶來的性能問題
因爲文件再也不更改,能夠充分利用文件系統緩存,只需載入一次,只要內存足夠,對該文件的讀取都會從內存讀取,性能高
利於生成緩存數據
利於對文件進行壓縮存儲,節省磁盤和內存存儲空間
壞處爲須要寫入新文檔時,必須從新構建倒排索引文件,而後替換老文件後,新文檔才能被檢索,致使文檔實時性差
文檔搜索實時性
解決方案是新文檔直接生成新的倒排索引文件,查詢的時候同時查詢全部的倒排文件,而後作結果的彙總計算便可
Lucene即是採用了這種方案,它構建的單個倒排索引稱爲segment,合在一塊兒稱爲index,與ES中的Index概念不一樣,ES中的一個shard對應一個Lucene Index
Lucene會有一個專門的文件來記錄全部的segment信息,稱爲commit point
refresh
segment寫入磁盤的過程依然很耗時,能夠藉助文件系統緩存的特性,現將segment在緩存中建立並開放查詢來進一步提高實時性,該過程在ES中被稱爲refresh
在refresh以前文檔會先存儲在一個buffer中,refresh時將buffer中的全部文檔清空並生成segment
ES默認每1秒執行一次refresh,所以文檔的實時性被提升到1秒,這也是ES被稱爲 近實時(Near Real Time)的緣由
translog
若是在內存中的segment尚未寫入磁盤前發生了宕機,那麼其中的文檔就沒法恢復了,如何解決這個問題呢?
ES引入translog機制,寫入文檔到buffer時,同時將該操做寫入translog
translog文件會即時寫入磁盤(fsync),6.x默認每一個請求都會落盤
flush
flush負責將內存中的segment寫入磁盤,主要作成以下的工做:
將translog寫入磁盤
將index buffer清空,其中的文檔生成一個新的segment,至關於一個refresh操做
更新commit point並寫入磁盤
執行fsync操做,將內存中的segment寫入磁盤
刪除舊的translog文件
flush發生的時機主要有以下幾種狀況:
間隔時間達到時,默認是30分鐘,5.x以前能夠經過
index.translog.flush_threshold_period
修改,以後沒法修改translog佔滿時,其大小能夠經過
index.translog.flush_threshold_size
控制,默認是512mb,每一個index有本身的translog
refresh
refresh發生的時機主要有以下幾種狀況:
間隔時間達到時,經過
index.settings.refresh_interval
來設定,默認是1秒index.buffer
佔滿時,其大小經過indices.memory.index_buffer_size
設置,默認爲JVM heap的10%,全部shard共享flush發生時也會發生refresh
刪除與更新文檔
segment一旦生成就不能更改,那麼若是你要刪除文檔該如何操做?
Lucene專門維護一個
.del
文件,記錄全部已經刪除的文檔,注意.del
上記錄的是文檔在Lucene內部的id在查詢結果返回前會過濾掉
.del
中全部的文檔
要更新文檔如何進行呢?
首先刪除文檔,而後再建立新文檔
總體視角
ES Index與Lucene Index的術語對照以下所示:
Segment Merging
隨着segment的增多,因爲一次查詢的segment數增多,查詢速度會變慢
ES會定時在後臺進行segment merge的操做,減小segment的數量
經過force_merge api能夠手動強制作segment merge的操做
參考:
慕課網 Elastic Stack從入門到實踐
更多內容請訪問個人我的博客:http://laijianfeng.org
打開微信掃一掃,關注【小旋鋒】微信公衆號,及時接收博文推送
本文分享自微信公衆號 - 小旋鋒(whirlysBigData)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。