大數據之分布式協調神器:Zookeeper選舉
前言
分布式系統設計成主從節點主要是為了保障數據一致性,主從設計是一種最直觀的數據一致性保障機制。
比如主從復制,主節點負責寫,從節點負責讀,提高讀的性能。從節點定期通過心跳與主節點溝通,一旦主節點掛掉了,從節點馬上接手主節點的任務。
但是主節點暫時失去響應,如瞬時負載過高,網絡擁塞或者其他原因導致主節點暫時失去響應,超過響應超時時間,這個時候從節點啟動,承擔起leader的職責,但是原先的主節點又恢復了服務。這個時候,如果沒有選舉機制(不能僅僅自己宣告自己是leader,還要廣而告之,讓其他服務器或者客戶端知道自己是leader),有可能會存在兩個leader節點,導致集群發生混亂。
所以有了以下關于大數據框架主從選舉的總結,趕快收藏吧!總有一個不經意時刻你會用到。
Zookeeper選舉
Zookeeper介紹
Zookeeper從設計模式角度來理解,是一個基于觀察者模式設計的分布式服務管理框架,它負責存儲和管理大家都關心的數據,然后接受觀察者的注冊,一旦這些數據的狀態發生了變化,Zookeeper就負責通知已經在Zookeeper上注冊的那些觀察者做出相應的反應。
Zookeeper特點
集群種只要有半數以上節點存活,Zookeeper集群就能正常提供服務。所以這就是選舉機制的奇數原則(Zookeeper適合安裝奇數臺服務)。
一個領導者Leaders和多個跟隨者Follower組成的集群。
Zookeeper的選舉機制
全新集群選舉
假設有五臺服務器組成的Zookeeper集群,它們的id從Service1到Service5,同時它們都是最新啟動的,也就是沒有歷史數據,在存放數據量這一點上,都是一樣的。假設這些服務器依序啟動,來看看會發生什么。
- 服務器1啟動,發起一次選舉。服務器1投自己一票。此時服務器1票數一票,不夠半數以上(3票),選舉無法完成,服務器1狀態保持為LOOKING;
- 服務器2啟動,再發起一次選舉。服務器1和2分別投自己一票并交換選票信息:此時服務器1發現服務器2的ID比自己目前投票推舉的(服務器1)大,更改選票為推舉服務器2。此時服務器1票數0票,服務器2票數2票,沒有半數以上結果,選舉無法完成,服務器1,2狀態保持LOOKING。
- 服務器3啟動,發起一次選舉。此時服務器1和2都會更改選票為服務器3。此次投票結果:服務器1為0票,服務器2為0票,服務器3為3票。此時服務器3的票數已經超過半數,服務器3當選Leader。服務器1,2更改狀態為FOLLOWING,服務器3更改狀態為LEADING。
- 服務器4啟動,發起一次選舉。此時服務器1,2,3已經不是LOOKING狀態,不會更改選票信息。交換選票信息結果:服務器3為3票,服務器4為1票。此時服務器4服從多數,更改選票信息為服務器3,并更改狀態為FOLLOWING。
- 服務器5啟動,同第4步一樣當FOLLOWING。
非全新集群選舉
對于運行正常的zookeeper集群,中途有機器down掉,需要重新選舉時,選舉過程就需要加入數據ID、服務器ID、和邏輯時鐘。
邏輯時鐘:這個值從0開始,每次選舉必須一致。小的選舉結果被忽略,重新投票(除去選舉次數不完整的服務器)。
數據id:數據新的version大,數據每次更新都會更新version。數據id大的勝出(選出數據最新的服務器)。
服務器id:即myid。數據id相同的情況下,服務器id大的勝出(數據相同的情況下,選擇服務器id最大,即權重最大的服務器)。
Kafka依賴Zookeeper的選舉
Kafka依賴ZK做了哪些事
ZooKeeper 作為給分布式系統提供協調服務的工具被 kafka 所依賴。在分布式系統中,消費者需要知道有哪些生產者是可用的,而如果每次消費者都需要和生產者建立連接并測試是否成功連接,那效率也太低了,顯然是不可取的。而通過使用 ZooKeeper 協調服務,Kafka 就能將 Producer,Consumer,Broker 等結合在一起,同時借助 ZooKeeper,Kafka 就能夠將所有組件在無狀態的條件下建立起生產者和消費者的訂閱關系,實現負載均衡。
Kafka選舉
Leader維護了一個動態的in-sync replica set (ISR),意為和leader保持同步的follower集合。當ISR中的follower完成數據的同步之后,leader就會給follower發送ack。如果follower長時間未向leader同步數據,則該follower將被踢出ISR,該時間閾值由replica.lag.time.max.ms參數設定。Leader發生故障之后,就會從ISR中選舉新的leader。
因此這個集合中的任何一個節點隨時都可以被選為leader。ISR在ZooKeeper中維護。ISR中有f+1個節點(follow+leader),就可以允許在f個節點down掉的情況下不會丟失消息并正常提供服。ISR的成員是動態的,如果一個節點被淘汰了,當它重新達到“同步中”的狀態時,他可以重新加入ISR。因此如果leader宕了,直接從ISR中選擇一個follower就行。
如果全掛呢?
一旦所有節點都down了,Kafka不會保證數據的不丟失。所以當副本都down掉時,必須及時作出反應。等待ISR中的任何一個節點恢復并擔任leader。
附:Kafka為什么要放棄ZK
本身就是一個分布式系統,但是需要另一個分布式系統來管理,復雜性無疑增加了。
部署的時候必須要部署兩套系統,的運維人員必須要具備的運維能力。
Controller故障處理:依賴一個單一節點跟進行交互,如果這個節點發生了故障,就需要從中選擇新的,新的選舉成功后,會重新從拉取元數據進行初始化,并且需要通知其他所有的更新。老的需要關閉監聽、事件處理線程和定時任務。分區數非常多時,這個過程非常耗時,而且這個過程中集群是不能工作的。
當分區數增加時,保存的元數據變多,集群壓力變大
基于ZooKeeper的Hadoop高可用
HDFS 高可用
介紹
一個典型的HA集群,NameNode會被配置在兩臺獨立的機器上,在任何時間上,一個NameNode處于活動狀態,而另一個NameNode處于備份狀態,活動狀態的NameNode會響應集群中所有的客戶端,備份狀態的NameNode只是作為一個副本,保證在必要的時候提供一個快速的轉移。所以對于HDFS來說,高可用其實就是針對NameNode的高可用。因為NameNode保存著集群的元數據信息,一旦丟失整個集群將不復存在。
主備切換控制器 ZKFailoverController:ZKFC 作為獨立的進程運行,對 NameNode 的主備切換進行總體控制。ZKFailoverController 能及時檢測到 NameNode 的健康狀況,在主 NameNode 故障時借助 Zookeeper 實現自動的主備選舉和切換,當然 NameNode 目前也支持不依賴于 Zookeeper 的手動主備切換。
原理
當HDFS的兩臺NN啟動時,ZKFC(Zookeeper FailoverController)也會啟動,ZKFC會向ZK上寫一個臨時序列化的節點(默認節點名是:/hadoop-ha)并取得和ZK的連接,一旦NN掛掉,那么ZKFC也會掛掉,該節點會被ZK自動刪除掉,ZKFC有Watcher機制(當子節點發生變化時觸動),另一個伴隨著NN啟動的ZKFC發現子節點變化了,是不是排在第一位,是,就通知第二臺NN開始接管,向JN同步數據(下載IDS文件并和FImage合并,并生成新的FImage),將元數據都變成最新的,若是掛掉的NN重新啟動,那么ZKFC還會向ZK寫個節點,等現接管的NN掛掉后再接管成為Master。
什么是ZKFC?
- ZKFC是一個Zookeeper的客戶端,它主要用來監測和管理NameNodes的狀態,每個NameNode機器上都會運行一個ZKFC程序,它的職責主要有:一是健康監控。ZKFC間歇性的ping NameNode,得到NameNode返回狀態,如果NameNode失效或者不健康,那么ZKFS將會標記其為不健康;
- Zookeeper會話管理。當本地NaneNode運行良好時,ZKFC將會持有一個Zookeeper session,如果本地NameNode為Active,它同時也持有一個“排他鎖”znode,如果session過期,那么次lock所對應的znode也將被刪除;
- 選舉。當集群中其中一個NameNode宕機,Zookeeper會自動將另一個激活。
內部操作與原理
HealthMonitor 初始化完成之后會啟動內部的線程來定時調用對應 NameNode 的 HAServiceProtocol RPC 接口的方法,對 NameNode 的健康狀態進行檢測。
HealthMonitor 如果檢測到 NameNode 的健康狀態發生變化,會回調 ZKFailoverController 注冊的相應方法進行處理。
如果 ZKFailoverController 判斷需要進行主備切換,會首先使用 ActiveStandbyElector 來進行自動的主備選舉。
ActiveStandbyElector 與 Zookeeper 進行交互完成自動的主備選舉。
ActiveStandbyElector 在主備選舉完成后,會回調 ZKFailoverController 的相應方法來通知當前的 NameNode 成為主 NameNode 或備 NameNode。
ZKFailoverController 調用對應 NameNode 的 HAServiceProtocol RPC 接口的方法將 NameNode 轉換為 Active 狀態或 Standby 狀態。
幾句話描述就是:ZooKeeper提供了簡單的機制來實現Acitve Node選舉,如果當前Active失效,Standby將會獲取一個特定的排他鎖,那么獲取鎖的Node接下來將會成為Active。
Yarn高可用
介紹
YARN ResourceManager 的高可用與 HDFS NameNode 的高可用類似但是 ResourceManager 不像 NameNode ,沒有那么多的元數據信息需要維護,所以它的狀態信息可以直接寫到 Zookeeper 上,并依賴 Zookeeper 來進行主備選舉。
內部操作與原理
- 在ZooKeeper上會有一個/yarn-leader-election/yarn1的鎖節點,所有的ResourceManager在啟動的時候,都會去競爭寫一個Lock子節點:/yarn-leader-election/yarn1/ActiveBreadCrumb,該節點是臨時節點。ZooKeepr能夠保證最終只有一個ResourceManager能夠創建成功。創建成功的那個ResourceManager就切換為Active狀態,沒有成功的那些ResourceManager則切換為Standby狀態。
- RM會把job的信息存放在zookeeper的/rmstore目錄下,active RM會向這個目錄寫app的信息。當active RM掛掉之后,standby RM會通過zkfc切換為active狀態,然后從zookeeper的/rmstore目錄下讀取相應的作業信息。重新構建作業的內存信息,啟動內部服務,開始接受NM的心跳信息,構建集群的資源信息,并且接受客戶端的作業提交請求。
其他與總結
在大數據領域,還有許多框架依賴與Zookeeper去選擇主從:比如Hbase集群,Kudu集群,Impala集群等等,最底層的原理大徑相同。
總結
選舉:Zookeeper能夠很容易的實現集群管理的功能,若有多臺Server組成一個服務集群,則必須要一個leader知道集群中每臺機器的服務狀態,從而做出調整重新分配服務策略。當集群中增加一臺或多臺Server時,leader同樣需要知道。Zookeeper不僅能夠維護當前的集群中機器的服務狀態,而且能夠選出一個leader來管理集群。
HA(分布式鎖的應用):Master掛掉之后迅速切換到slave節點。