ZooKeeper介紹

Hoking發表於2018-08-21

ZooKeeper

        ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要元件。它是一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、域名服務、分散式同步、組服務等。ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。ZooKeeper包含一個簡單的原語集, 提供Java和C的介面。ZooKeeper程式碼版本中,提供了分散式獨享鎖、選舉、佇列的介面,程式碼在zookeeper\src\recipes。其中分佈鎖和佇列有Java和C兩個版本,選舉只有Java版本。

ZooKeeper原理

       ZooKeeper是以Fast Paxos演算法為基礎的,Paxos 演算法存在活鎖的問題,即當有多個proposer交錯提交時,有可能互相排斥導致沒有一個proposer能提交成功,而Fast Paxos作了一些優化,通過選舉產生一個leader (領導者),只有leader才能提交proposer,具體演算法可見Fast Paxos。因此,要想弄懂ZooKeeper首先得對Fast Paxos有所瞭解。

ZooKeeper的基本運轉流程:

1、選舉Leader。

2、同步資料。

3、選舉Leader過程中演算法有很多,但要達到的選舉標準是一致的。

4、Leader要具有最高的執行ID,類似root許可權。

5、叢集中大多數的機器得到響應並接受選出的Leader。

Paxos演算法

在paxos演算法中,分為4種角色:

  Proposer :提議者

  Acceptor:決策者

  Client:產生議題者

  Learner:最終決策學習者

       上面4種角色中,提議者和決策者是很重要的,其他的2個角色在整個演算法中應該算做打醬油的,Proposer就像Client的使者,由Proposer使者拿著Client的議題去向Acceptor提議,讓Acceptor來決策。這裡上面出現了個新名詞:最終決策。現在來系統的介紹一下paxos演算法中所有的行為:

Proposer提出議題

Acceptor初步接受 或者 Acceptor初步不接受

       如果上一步Acceptor初步接受則Proposer再次向Acceptor確認是否最終接受Acceptor 最終接受 或者Acceptor 最終不接受

上面Learner最終學習的目標是Acceptor們最終接受了什麼議題?注意,這裡是向所有Acceptor學習,如果有多數派個Acceptor最終接受了某提議,那就得到了最終的結果,演算法的目的就達到了。畫一幅圖來更加直觀:

 

       Zookeeper所使用的zad協議也是類似paxos協議的。所有分散式自協商一致性演算法都是paxos演算法的簡化或者變種。Client是使用zookeeper服務的機器,Zookeeper自身包含了Acceptor, Proposer, Learner。Zookeeper領導選舉就是paxos過程,還有Client對Zookeeper寫Znode時,也是要進行Paxos過程的,因為不同Client可能連線不同的Zookeeper伺服器來寫Znode,到底哪個Client才能寫成功?需要依靠Zookeeper的paxos保證一致性,寫成功Znode的Client自然就是被最終接受了,Znode包含了寫入Client的IP與埠,其他的Client也可以讀取到這個Znode來進行Learner。也就是說在Zookeeper自身包含了Learner(因為Zookeeper為了保證自身的一致性而會進行領導選舉,所以需要有Learner的內部機制,多個Zookeeper伺服器之間需要知道現在誰是領導了),Client端也可以Learner,Learner是廣義的。

 

ZAB協議(ZooKeeper Atomic Broadcast原子訊息廣播協議)

zab協議所有事務請求必須由leader協調,首先leader發起proposal訊息,大多數server同意後,然後leader傳送commit訊息。

zxid編號

低32位為計數器,客戶端每次請求+1

高32位為epochID,每次選舉新leader+1

狀態和階段

Looking:系統剛啟動時或者Leader崩潰後正處於選舉狀態

Following:Follower節點所處的狀態,Follower與Leader處於資料同步階段

Leading:Leader所處狀態,當前叢集中有一個Leader為主程式

 

zookeeper主要分為5個階段,選舉,發現,同步,廣播

1 選舉:Looking狀態中選舉出Leader節點,Leader的lastZXID總是最新的

2 發現:Follower節點向準Leader推送FOllOWERINFO,該資訊中包含了上一週期的epoch,接受準Leader的NEWLEADER指令,檢查newEpoch有效性,準Leader要確保Follower的epoch與ZXID小於或等於自身的。

3 同步:將Follower與Leader的資料進行同步,由Leader發起同步指令,最總保持叢集資料的一致性

4 廣播:Leader廣播Proposal與Commit,Follower接受Proposal與Commit;

 

選舉

zab必須確保選舉出來的leader具有最大的zxid(這和raft很像啊)。這裡要注意一下,和raft一樣,選舉可能會出現兩種結果:

□上一輪的多數派(此時leader zxid可能不是最大的,需要同步的時候呼叫trunc)

□上一輪的少數派,leader zxid真的是最大的(但是這個最大的zxid沒有提交,在同步階段提交?)

過程詳解:

1、每個Follower都向其他節點傳送選自身為Leader的Vote投票請求,等待回覆;

2、Follower接受到的Vote如果比自己的ZXID更新時則投票,並更新自身的Vote,否則拒絕投票;

3、每個Follower中維護著一個投票記錄表,當某個節點收到過半的投票時,結束投票並把該Follower選為Leader,投票結束;

恢復(發現和同步)

發現

1、leader生成新的zxid和epoch,接受follower傳送來的FOllOWERINFO(含有當前節點的LastZXID)

2、leader向follower傳送NEWLEADER;Leader根據follower傳送過來的LastZXID根據資料更新策略向Follower傳送更新指令;

同步

1、SNAP:如果follower資料太老,epoch還在上上一輪,leader將傳送快照snap指令給follower同步

2、DIFF:正常同步階段

3、TRUNC:如果Follower是上一輪的少數派(通過對比ztid),傳送TRUNC指令讓follower丟棄這段資料

廣播

進入正常leader提交階段,產生遞增的zxid,接受半數投票後,再提交。

 

與raft的區別

我覺得zab和raft沒有本質的區別,它們唯一的不同點就是如何處理上一個leader的殘留日誌。

·raft中,需要本輪iterm有日誌提交後,才提交以前的

·zab中,在同步階段全部解決

 

資料整理與引用

1、https://baike.baidu.com/item/zookeeper/4836397?fr=aladdin

2、https://www.cnblogs.com/endsock/p/3480093.html

3、https://www.cnblogs.com/jxwch/p/6433310.html

4、https://www.cnblogs.com/felixzh/p/5869212.html

5、https://blog.csdn.net/liu857279611/article/details/70495413

6、https://blog.csdn.net/z69183787/article/details/54730322

7、https://blog.csdn.net/z69183787/article/details/53023578

8、https://blog.csdn.net/hohoo1990/article/details/78617336