zk是分布式協調工具,可以實現其他客戶端集群的leader選舉,分布式鎖。
zk集群自身則是使用zab協議經行選舉,以及資料同步
可以利用zk節點的特性來實現獨佔鎖。就是同級節點的唯一性。多個程序往zk節點下建立乙個相同名稱的節點,只有乙個能成功,其他都失敗。建立失敗的節點全部通過zk的watch機制來監聽zk這個字節點的變化,一旦監聽到子節點的刪除事件,則再次觸發所有的程序去寫鎖。
這種方式實現很簡單,但是會產生驚群反應。簡單來說,就是如果存在多個客戶端等待鎖,當監聽到程序釋放節點後,zk會在短時間內傳送大量子節點變更事件給所有獲取鎖的客戶端,然後只有乙個程序獲取鎖。
解決方式:利用有序節點來實現分布式鎖。
每個客戶端都往指定的節點下註冊臨時有序節點,越早建立的節點,節點的順序編號越小。我們可以判斷子節點中最小的節點設定為獲取到鎖,如果自己的節點不是最小的節點,以為著沒有獲取到鎖。
這個實現過程,與剛剛說的流程最大的差別是,每個節點只需要監聽比自己小的節點,當比自己小的節點刪除以後,客戶端會收到watch事件,此時再次判斷自己的節點是不是所有子節點中最小的。如果是,就獲取到鎖。否則,重複這個過程。這樣就不會產生驚群效應,因為每個客戶端只需要監控乙個節點。(後續分析curator實現分布式鎖原始碼)
參與選舉的所有節點,會建立乙個順序節點,其中最小的節點會設定master節點,沒搶到leader的節點都監聽前乙個節點的刪除事件,在前乙個節點刪除後重新搶主。當master節點手動呼叫close方法或者master節點掛掉的時候,後續的節點會繼續搶占master。
leaderselector在leader釋放領導權以後,可以繼續參與競爭。
首先要知道,zk集群是通過三種不同的集權角色來組成整個高效能集群的。在zk中,客戶端會隨機連線到zk集群中的乙個節點,如果是讀請求,就直接從當前節點中讀取資料,如果是寫請求,那麼請求就會被**給leader提交事務,然後leader會廣播事務,只有超過半數節點寫入成功(所以,zk集群一般是奇數,2n+1個),那麼寫請求就會被提交。(類似 2pc事務。)
那麼問題來了,
1 集群中的leader節點如何選舉出來。
2 leader節點崩潰以後,整個集群無法處理寫請求,如何快速從其他節點裡面選舉出新的leader呢 ?
3 leader節點如何與follower節點資料保持一致。
zab協議(zookeeper atomic broadcast)協議是為分布式協調服務zk專門設計的一種支援崩潰恢復的原子廣播協議。在zk中,主要依賴zab協議來實現分布式資料一致性,基於該協議,zk實現了一種主備模式的系統架構來保持集群中各個副本之間的資料一致性。
zab協議包含兩種基本模式,分別是:
1 崩潰恢復
2 原子廣播
當整個集群在啟動時,或者當leader節點出現網路中斷,崩潰等情況時,zab協議就會進入恢復模式並選舉產生新的leader,當leader伺服器選舉出來後,並且集群中有過半的機器和該leader節點完成資料同步後(同步指的是資料同步,用來保證集群中過半的機器能夠和leader伺服器的資料狀態保持一致),zab協議就會退出恢復模式。當集群中已經有過半的follower節點完成了和leader狀態同步以後,那麼整個集群就進入了訊息廣播模式。這個時候,在leader節點正常工作時,啟動一台新的伺服器加入到集群,那麼這個伺服器直接進入資料恢復模式,和leader節點直接進行資料同步,同步完成後,即可正常對外提供非事務請求的處理。
需要注意的是: leader節點可以處理事務請求和非事務請求,follower節點只能處理非事務請求,如果follower節點接收到事務請求,會把請求**給leader伺服器。
訊息廣播的過程實際上是乙個簡化版本的二階段提交。
1 leader接收到訊息請求後,將訊息賦予乙個全域性唯一的64位自增id,叫zxid,通過zxid的大小比較既可以實現因果有序這個特徵。
2 leader為每個follower準備了乙個fifo佇列,(通過tcp協議來實現,以實現全域性有序這個特點)將帶有zxid的訊息作為乙個提案(proposal)分發給所有的follower。
3 當follower接收到proposal,先把proposal寫到磁碟,寫入成功以後再向leader返回乙個ack。
4 當leader接收到合法數量(超過半數節點)的ack後,leader就會像這些follower傳送commit命令。同時在本地會執行該訊息。
5 當follower收到訊息的commit後,會提交該訊息。
這裡需要注意的是:
leader的投票過程,不需要observer的ack,也就是observer不需要參與投票過程,但是observer必須要同步leader的資料,從而在處理請求的時候保證資料的一致性。
前面我們已經清楚了zab協議中的訊息廣播過程,zab協議的這個基於原子廣播協議的 訊息廣播過程,在正常情況下是沒有任何問題的,但是一旦leader節點崩潰,或者由於網路問題導致leader伺服器失去了過半的follower節點,那麼就會進入到崩潰恢復狀態。在崩潰恢復狀態下,zab協議需要做兩件事:
1 選舉出新的leader
2 資料同步
前面說訊息廣播時,知道zab協議的訊息廣播機制時簡化版的2pc協議,這種協議只需要集群中過半的節點相應提交即可。但是他無法處理leader伺服器崩潰帶來的資料不一致問題。
如果乙個事務proposal在一台伺服器上被處理成功,那麼這個事務應該在所有機器上都處理成功,哪怕出現故障。
當leader收到合法數量follower的acks後,就會向各個follower節點發布廣播commit命令,同時也會在本地執行commit命令,並向連線的客戶端返回成功。 但是,如果在各個follower收到commit命令之前,leader就掛了,導致剩下的伺服器沒有執行該訊息怎麼辦?
當leader收到事務請求後生成proposal後,就掛了,其他follower並沒有收到此proposal,因此經過恢復模式重新選取了leader後,這條訊息是被跳過的 。此後,之前掛了的leader,重新啟動並註冊成follower,它保留了被跳過取消的proposal狀態,與整個系統時不一致的,需要被刪除。
zab協議要滿足上面兩種情況,就必須設計乙個leader選舉演算法,能夠確保已經被leader提交的事務proposal能夠提交。同時,丟棄已經被跳過的proposal。
針對這個要求
1 如果 leader 選舉演算法能夠保證新選舉出來的 leader 伺服器擁有集群中所有機器最高編號(zxid 最大)的事務proposal,那麼就可以保證這個新選舉出來的 leader 一定具有已經提交的提案。因為所有提案被 commit 之前必須有超過半數的 follower ack,即必須有超過半數節點的伺服器的事務日誌上有該提案的 proposal,因此,只要有合法數量的節點正常工作,就必然有乙個節點儲存了所有被 commit 訊息的 proposal 狀態
2. 另外乙個,zxid 是 64 位,高 32 位是 epoch 編號,每經過一次 leader 選舉產生乙個新的 leader,新的 leader會將 epoch 號+1,低 32 位是訊息計數器,每接收到一條訊息這個值+1,新 leader 選舉後這個值重置為 0.這樣設計的好處在於老的 leader 掛了以後重啟,它不會被選舉為 leader,因此此時它的 zxid 肯定小於當前新的leader。當老的 leader 作為 follower 接入新的 leader
後,新的 leader 會讓它將所有的擁有舊的 epoch 號的未被 commit 的 proposal 清除.
手續會閱讀zk原始碼,從**層面來剖析zk的zab協議。
ZK初時 Zookeeper的工作原理
通俗來講,zookeeper 的核心是原子廣播,這個機制保證了各個 server 之間的同步。實現這個機制的協議叫做 zab 協議。zab 協議有兩種模式,它們分別是恢復模式和廣播模式。當服務啟動或者在領導者崩潰後,zab 就進入了恢復模式,當領導者被選舉出來,且大多數 server 的完成了和 l...
zk學習之zk集群搭建
1 進入conf資料夾,編輯zoo.cfg檔案 新增 1 datadir zk的工作目錄,必須配置 datalogdir zk的日誌檔案,可以不配,預設在datadir c l 2 新增主從zk server.1表示zk節點id為1的節點 server.2表示zk節點id為2的節點 server.3...
ZK安裝 ZK配置 ZK集群部署踩過的大坑
天天採坑 來來咱們一起來填zookeeper的坑呀!解決坑一定要注意zk根目錄下的神器,那就是logs目錄下的日誌,第一坑 錯誤 找不到或無法載入主類 org.apache.zookeeper.server.quorum.quorumpeermain 檢視日誌的時候發現 錯誤 找不到或無法載入主類 ...