常見組件的集群原理(Redis、ES、NSQ)


今天發現大家對NSQ等組件的集群原理還不了解,所以這遍文章對一些常見組件的集群原理做一個匯總整理。我會不定期更新,增加一些新的組件或修改錯誤。

1 NSQ

NSQ集群比較簡單,主要包含4個部分,一是生產者(圖上沒畫)、二是nsq實例(nsqd)、三是服務發現nsqlookupd、四是消費者(Comsumer)。
這4個部分的工作方式如下:

  1. 生產者
  • 生產者需要指定將消息寫入哪個實例nsqd
  • 當一個nsqd實例宕機時,生產者可以選擇將消息寫到其他的實例
  • 生產者也可以將同一條消息寫入兩個nsqd(HA)
  1. nsqd
  • 消息不會在nsqd之間傳遞,生產者把消息寫到哪個nsqd就只能在該nsqd消費
  • 不同的nsqd可以接收同一個生產者的相同的消息,參考生產者的說明
  • nsqd會將自己的服務信息廣播給集群內的nsqlookupd
  1. 服務發現nsqlookupd
  • nsqlookupd與集群內的所有nsqd建立連接,檢測實例的狀態,並接收實例廣播過來的服務注冊
  • nsqlookupd接收消費者客戶端的服務發現請求,將對應的實例返回給消費者(這里可以是多個實例)
  • 一個集群可以有多個nsqlookupd
  1. 消費者comsumer
  • 消費者可以與nsqd直連,但為了防止單點故障,不應該有這種固定的關系
  • 官方推薦走服務發現nsqlookupd,參考生產者的說明,當一個nsqd宕機時,生產者可以將消息寫入其他的nsqd,或者為了HA,生產者可以雙寫

針對上述特性說明,我們可以得出以下結論或支撐系統高可用的方案:

  • 當一個nsqd宕機時,這台機上尚未消費且尚未落盤的消息會丟失;集群本身不提供副本和分片
  • 鑒於上一條,對於冪等且不可丟失的消息,生產者可以選擇雙寫,一條消息同時寫兩個實例
  • 當正在寫的nsqd宕機時,生產者可以選擇寫入其他的nsqd。前提是消費者通過nsqlookupd完成服務發現,及時感知集群的變化;或者消費者可以同時連上集群內所有的Nsqd實例
  • 生產者可以做一定的負載均衡,將消息分散生產到不同的nsqd中

2 Elasticsearch

2.1 拓撲結構

ES集群涉及數據遷移、負載均衡和HA等,所以會比NSQ集群更復雜些,下面我們通過一張圖來簡單介紹下:

ES的節點可以通過兩組配置項來決定每個節點類型,即"node.master: true/false"和"node.data: true/false",具體類型如下表:

node.master node.data 是否參與選主 是否保存數據 是否參與計算 對應上圖節點
true true Node A/B
true false Node C
false true Node D
false false Node E

特殊的,像Node E這種又不參與選主,又不保存數據的節點,也是有用的,它可以用來處理用戶請求。所有的節點都可以接收並處理用戶請求。具體邏輯見后續章節。
ES集群還支持其他的節點類型,在此不展開討論。
集群內所有節點理論上兩兩相連(網絡異常時允許部分節點之間通訊中斷,保證最終整個集群是拓撲連續的即可)。每個節點都會保存與其相連的其他節點的信息,用於選主和路由。節點之間通過Gossip謠言傳播算法實現數據交換和最終一致性,具體的原理細節這里就不討論了。

2.2 數據分布

ES支持數據分片和分片副本:

  • 主分片與副本分片一般分布在不同的節點(HA高可用)
  • 不同的主分片可以在同一個節點
  • 數據更新只能發生在主分片
  • 查詢請求可以在主副分片
  • 當主分片丟失時,會自動選擇一個最新的副本分片作為主

分片分布在哪個節點上是不固定的,隨着集群的數據變化和節點的增加刪除,分片會在不同節點之間移動。這個由master主節點來負責協調。具體參見“master主節點”章節。

2.3 數據訪問

集群所有節點均可接收用戶請求
2.1章節提到每個節點會保存其他節點的信息,所以當一個用戶請求到來時,當前節點負責解析用戶請求,並從本地節點列表中選擇有相關分片的節點(數據分片往往被打散到不同的節點)將請求轉發過去。

對於寫請求:

  1. Node A收到用戶請求,解析后確定需要寫Node B所保存的主分片,則Node A將請求轉發給Node B
  2. Node B完成主分片的寫入(注意,只有主分片能寫,副本分片從主分片同步數據)
  3. Node B將數據同步給集群內其他副本分片,待所有分片均返回后,響應Node A寫入成功
  4. Node A響應用戶請求

對於讀請求:

  1. Node A收到用戶請求,解析后確認涉及哪些分片,從本地節點列表中找出有相關分片的節點將請求轉發過去
  2. 各分片完成查詢,將數據返回給Node A
  3. Node A將數據運算匯總后,響應用戶請求

2.4 master主節點

主節點是由集群自動選舉出來的
集群內有且只能有一個master主節點,它負責集群的協調工作,比如新節點加入、分片的轉移等。
根據2.1章節的描述,只有node.master配置為true的節點才有可能成為主節點。

集群選舉

  1. 選舉由node.master配置為true的節點發起,當某個候選節點發現當前集群缺少master的時候,會主動發起選舉(節點之間會相互通過ping交換信息,包括主節點信息,如果超過半數的節點都連不上主節點時,就認為沒有主節點)
  2. 選舉的方式是集群所有節點投票,投票規則是每個節點都選擇本地列表中version最高的(如果存在並列最高,則選id最小的那個節點),節點通過join指令投票。
  3. 被選節點通過收集join的次數,超過集群節點總數的一半+1的節點選自己為主節點時,選舉即成功。
  4. 否則超時開啟下一輪選舉,直到集群選出master。

關於腦裂
當集群存在兩個或以上的master時,我們稱之為腦裂。這種情況會導致集群的一致性受到威脅。
略有遺憾的是ES存在小概率的腦裂問題。比如當Node A發起選舉,Node X投了一票;但選舉遲遲未成功,接着又有個節點發起了一輪投票,剛好這時Node X發現Node B的版本更高,又投了一票給Node B。於是Node X投出了兩票,條件契合的情況下,Node A/B可能同時認為自己被選上。這種情況可以通過引入選舉周期來解決,同一周期一個節點只投一票,最終選擇周期最新的節點為主。

特別注意:只有兩個節點的集群,一旦通訊異常,master就選不出來了,因為拿不到總節點數/2 + 1的票數
類似的,當集群有超過半數的節點宕機,集群將變的不可用。

2.5 節點發現和退出

當有節點需要加入集群時,通過給它配置discovery.zen.ping.unicast.hosts: [xx.xx.xx.xx, yy.yy.yy.yy]參數來完成自動發現,加入集群。原理是節點會向上述hosts列表發送請求,尋找master,然后join master。該hosts建議配置成所有的主候選節點。
節點需要退出時,先標記待退出狀態,待master將分片全部移走時,才能退出集群。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM