公號:碼農充電站pro
主頁:https://codeshellme.github.iohtml
ES 是一個分佈式的集羣,具備高可用性和可擴展性:node
ES 集羣git
ES 集羣中能夠有一個或多個節點,ES 經過集羣名字來區分不一樣的集羣,集羣名能夠經過 cluster.name
進行設置,默認爲 "elasticsearch"。github
ES 的一個節點就是一個 Java 進程,因此一臺機器能夠運行一個或多個節點,生產環境建議一臺機器只運行一個節點。算法
每一個節點啓動以後,都會分配一個 UID
,並保存在 data
目錄下。shell
每一個節點都有節點名字,節點名可經過 node.name
設置。緩存
Master 節點的職責:網絡
集羣的狀態包括:架構
全部的節點有保存了集羣的狀態信息,但只有主節點可以修改集羣狀態。app
在 ES 集羣中,只有 Master-eligible 節點能夠被選舉爲 Master 節點。
每一個節點啓動後默認就是 Master-eligible 節點,能夠經過設置 node.master
爲 false
來禁止成爲 Master-eligible 節點。
默認狀況下,集羣中的第一個節點啓動後,會將本身選舉爲 Master 節點。
集羣中的每一個節點都保存了集羣的狀態,但只有 Master 節點可以修改集羣的狀態信息。
用於保存 ES 數據的節點,就是 Data 節點,它對數據擴展起到了相當重要的做用。
Coordinating 節點叫作協調節點,它負責接收 Client 的請求,將請求分發到合適的節點,並最終彙總結果返回給 Client。
在 ES 中,全部的節點都是 Coordinating 節點。
Ingest 節點用於對數據預處理,經過添加一些 processors 來完成特定的處理。
Ingest 節點是在 ES 5.0 後引入的一種節點類型,能夠達到必定的 Logstash 的功能。
默認狀況下,全部的節點都是 Ingest 節點。
理論上,一個節點能夠扮演過多個角色,但生產環境中,建議設置單一角色。
節點的類型能夠經過下面參數進行配置:
節點類型 | 配置參數 | 默認值 |
---|---|---|
Master-eligible | node.master | true |
Data Node | node.data | true |
Ingest Node | node.ingest | true |
Coordinating Node | 無 | 設置上面 3 個都爲 false |
咱們能夠經過下面的 API 來查看整個集羣的健康狀態:
集羣有 3 種級別的健康狀態:
green
:全部的主分片與副本分片都正常。yellow
:全部的主分片都正常,某些副本分片不正常。red
:部分主分片不正常。咱們也能夠經過 Kibana 中的索引管理,來查看每一個索引的健康狀態:
索引的狀態級別與集羣的狀態級別一致。
腦裂問題是分佈式系統中的經典問題。
腦裂問題指的是,當出現網絡故障時,一些節點沒法與另外一些節點鏈接,這時這兩大部分節點會各自爲主;當網絡恢復時,也沒法恢復成一個總體。
如何避免腦裂問題
要限定一個選舉條件,設置 Quorum(仲裁):
只有當 Master eligible 節點數大於 Quorum 時,才能進行選舉。
在 ES 7.0 以前,爲了不腦裂問題,須要手動設置 discovery.zen.minimum_master_nodes
爲 Quorum。
在 ES 7.0 以後,ES 會本身處理腦裂問題,不須要用戶處理。
ES 中的分片(Shard)用於存儲數據,是存儲的最小單元。
分片有兩種:主分片(Primary Shard)和副本分片(Replica Shard),副本分片是主分片的拷貝。
主分片用於數據水平擴展的問題,主分片數在索引建立時指定,以後不容許修改。
副本分片用於解決數據高可用的問題,副本分片數能夠動態調整。
分片數能夠經過索引的 setting
進行設置,好比:
PUT /index_name { "settings" : { "number_of_shards" : 3, "number_of_replicas" : 1 } }
其中 number_of_shards
表示主分片數,number_of_replicas
表示每一個主分片的副本分片數。
若是一個集羣有 3 個數據節點,某個索引有 3 個主分片,1 一個副本分片,那麼它的節點分佈會像下面這樣:
其中藍色框爲主分片,白色框爲副本分片。
ES 在分配主副分片時,會將副本分片與主分片應該在不一樣的節點上。
主分片和副本分片分別分佈到不一樣的數據節點上,這樣的話,若是有某個數據節點宕機,也不會影響整個系統的使用。
ES 7.0 開始,默認的主分片數爲 1,默認的副本分片數爲 0。在生產環境中,副本分片數至少爲 1。
分片數設置不合理引起的問題:
根據這樣的配置(3 個主分片,1 個副本分片),若是隻有一個節點,則會致使副本分片沒法分配(ES 會將主副分片分配在不一樣的節點上),集羣狀態爲 yellow。
若是此時增長一個數據節點,那麼副本分片就得以分配,集羣具有了故障轉移能力,集羣狀態轉爲 green。
若是此時再增長一個數據節點,那麼主節點會從新分配分片的分佈。同時,集羣的總體能力也獲得了提高。
若是此時有一個節點發生故障,好比主節點發生了故障:
此時集羣的狀態會變爲 yellow,而後會從新選舉主節點(假設選舉了 Node2 爲主節點),而且原來的 Node1 節點上的 p0 和 R1 分片,會被分配到 Node2 和 Node3 上。
集羣調整完畢後,會從新恢復到 green 狀態。
ES 中的一個分片對應了 Lucene 中的一個 Index。
在 Lucene 中,單個倒排索引文件稱爲 Segment。
Segment 是不可變的,當有新的文檔寫入時,會生成新的 Segment(放在文件系統緩存中)。
多個 Segment 彙總在一塊兒稱爲 Lucene 中的 Index,也就是 ES 中的分片。
ES 的文檔在寫入時,會先放在 Index Buffer
(內存) 中,當 Index Buffer 的空間被佔用到必定程度/時間週期後,會 Refresh 到 Segment 中,Index Buffer 則會被清空。
Refresh 的刷新頻率能夠經過 index.refresh_interval 參數進行設置,默認爲 1 秒。
或者當 Index Buffer 被佔用到 JVM 的 10%(默認值),也會觸發 Refresh。
當文檔被 Refresh 到 Segment 後,就能夠被 ES 檢索到了。
寫入文檔時,會先放在 Index Buffer
中,而 Index Buffer 是在內存中,爲了防止內存意外(好比斷電)丟失,在寫入 Index Buffer 的同時,也會寫到 Transaction log(磁盤)中。
一個 Transaction log 默認是 512M。
ES 的 Flush 會觸發如下操做:
Flush 操做默認 30 分鐘調用一次,或者當 Transaction log 滿(默認 512 M)時也會觸發 Flush。
當愈來愈多的 Segment 被寫入到磁盤後,磁盤上的 Segment 會變得不少,ES 會按期 Merge 這些 Segment。
文檔的刪除操做並不會立刻被真正的刪除,而是會寫入 del 文件中,Merge 操做也會刪除該文件。
Merge 操做能夠由 ES 自動觸發,也能夠手動強制 Merge,語法以下:
POST index_name/_forcemerge
文檔會均勻分佈在分片上,充分利用硬件資源,避免資源利用不均。
文檔到分片的路由算法:
shard_index = hash(_routing) % number_of_primary_shards
_routing
值爲文檔 id。_routing
的值也能夠自行指定。正是由於文檔的路由算法是基於主分片數來計算的,因此主分片數一旦肯定之後,就不能修改。
_routing 的設置語法以下:
POST index_name/_doc/doc_id/routing=xxx { # 文檔數據 }
文檔的 Write 操做(插入,更新,刪除)的流程:
ES 的搜索過程分兩個階段:
From + Size
個排好序的文檔 ID 和排序值(score),給 Coordinating 節點。From + Size
個文檔的 ID。Multi Get
的方式,到相應的分片獲取具體的文檔信息,並返回給用戶。這兩個階段合稱爲 Query Then Fetch。
(本節完。)
推薦閱讀:
歡迎關注做者公衆號,獲取更多技術乾貨。