1. 程式人生 > >zookeeper基本工作原理

zookeeper基本工作原理

ZooKeeper是什麼?

ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是Google的Chubby一個開源的實現,它是叢集的管理者,監視著叢集中各個節點的狀態根據節點提交的反饋進行下一步合理操作。最終,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。zookeeper是一個檔案系統,每個子目錄項如 NameService 都被稱作為znode,和檔案系統一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在於znode是可以儲存資料的。 

有四種類型的znode: 

1、PERSISTENT-持久化目錄節點
客戶端與zookeeper斷開連線後,該節點依舊存在
2、PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點
客戶端與zookeeper斷開連線後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號
3、EPHEMERAL-臨時目錄節點
客戶端與zookeeper斷開連線後,該節點被刪除
4、EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點
客戶端與zookeeper斷開連線後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號 

zookeeper能做什麼?

1、命名服務--在zookeeper的檔案系統裡建立一個目錄,即有唯一的path。在我們使用tborg無法確定上游程式的部署機器時即可與下游程式約定好path,通過path即能互相探索發現。

2、叢集管理--具有通知機制進行管理服務的上線下線,以及註冊中心的叢集選主並進行原子廣播。

3、配置管理--znode是可以存放資料的,可以把系統配置全部放到zookeeper上去,儲存在 Zookeeper 的某個目錄節點中,然後所有相關應用程式對這個目錄節點進行監聽,一旦配置資訊發生變化,每個應用程式就會收到 Zookeeper 的通知,然後從 Zookeeper 獲取新的配置資訊應用到系統中就好。當然現在也有一些常用的配置中心,如Apollo。

4、分散式鎖--分散式服務下進行節點的建立以及刪除

5、佇列管理--所有寫操作都被嚴格編號排序入隊進行管理。編號嚴格遞增,當一個節點接受了一個
   編號為100的寫操作,之後又接受到編號為99的寫操作(因為網路延遲等很多不可預見原因),它馬上能意識到自己 資料
   不一致了,自動停止對外服務並重啟同步過程。

zookeeper的各種角色:

 

zookeeper的核心協議(ZAB協議):

Paxos 演算法是萊斯利•蘭伯特(英語:Leslie Lamport)於 1990 年提出的一種基於訊息傳遞且 具有高度容錯特性的一致性演算法。

  分散式系統中的節點通訊存在兩種模型:共享記憶體(Shared memory)和訊息傳遞(Messages passing)

。基於訊息傳遞通訊模型的分散式系統,不可避免的會發生以下錯誤:程序可能會 慢、被殺死或者重啟,訊息可能會延遲、丟失、重複,在基礎 Paxos 場景中,先不考慮可能 出現訊息篡改即拜占庭錯誤(Byzantine failure,即雖然有可能一個訊息被傳遞了兩次,但是 絕對不會出現錯誤的訊息)的情況。Paxos 演算法解決的問題是在一個可能發生上述異常的分散式系統中如何就某個值達成一致,保證不論發生以上任何異常,都不會破壞決議一致性。

  Paxos 演算法使用一個希臘故事來描述,在 Paxos 中,存在三種角色,分別為

    Proposer(提議者,用來發出提案 proposal)

    Acceptor(接受者,可以接受或拒絕提案)

    Learner(學習者,學習被選定的提案,當提案被超過半數的 Acceptor 接受後為被批准)

  下面更精確的定義 Paxos 要解決的問題:

    1、決議(value)只有在被 proposer 提出後才能被批准

    2、在一次 Paxos 演算法的執行例項中,只批准(chose)一個 value

    3、learner 只能獲得被批准(chosen)的 value

  ZooKeeper 的選舉演算法有兩種:一種是基於 Basic Paxos(Google Chubby 採用)實現的,另外 一種是基於 Fast Paxos(ZooKeeper 採用)演算法實現的。系統預設的選舉演算法為 Fast Paxos。 並且 ZooKeeper 在 3.4.0 版本後只保留了 FastLeaderElection 演算法。

  ZooKeeper 的核心是原子廣播,這個機制保證了各個 Server 之間的同步。實現這個機制的協 議叫做 ZAB 協議(Zookeeper Atomic BrodCast)。 ZAB 協議有兩種模式,它們分別是崩潰恢復模式(選主)和原子廣播模式(同步)

  1、當服務啟動或者在領導者崩潰後,ZAB 就進入了恢復模式,當領導者被選舉出來,且大 多數 Server 完成了和 leader 的狀態同步以後,恢復模式就結束了。狀態同步保證了 leader 和 follower 之間具有相同的系統狀態。

     2、當 ZooKeeper 叢集選舉出 leader 同步完狀態退出恢復模式之後,便進入了原子廣播模式。 所有的寫請求都被轉發給 leader,再由 leader 將更新 proposal 廣播給 follower

   為了保證事務的順序一致性,zookeeper 採用了遞增的事務 id 號(zxid)來標識事務。所有 的提議(proposal)都在被提出的時候加上了 zxid。實現中 zxid 是一個 64 位的數字,它高 32 位是 epoch 用來標識 leader 關係是否改變,每次一個 leader 被選出來,它都會有一個新 的 epoch,標識當前屬於那個 leader 的統治時期。低 32 位用於遞增計數。  

   這裡給大家介紹以下 Basic Paxos 流程:

1、選舉執行緒由當前 Server 發起選舉的執行緒擔任,其主要功能是對投票結果進行統計,並選 出推薦的 Server

2、選舉執行緒首先向所有 Server 發起一次詢問(包括自己)

3、選舉執行緒收到回覆後,驗證是否是自己發起的詢問(驗證 zxid 是否一致),然後獲取對方 的 serverid(myid),並存儲到當前詢問物件列表中,最後獲取對方提議的 leader 相關資訊 (serverid,zxid),並將這些資訊儲存到當次選舉的投票記錄表中

4、收到所有 Server 回覆以後,就計算出 id 最大的那個 Server,並將這個 Server 相關資訊設 置成下一次要投票的 Server

5、執行緒將當前 id 最大的 Server 設定為當前 Server 要推薦的 Leader,如果此時獲勝的 Server 獲得 n/2 + 1 的 Server 票數, 設定當前推薦的 leader 為獲勝的 Server,將根據獲勝的 Server 相關資訊設定自己的狀態,否則,繼續這個過程,直到 leader 被選舉出來。

   通過流程分析我們可以得出:要使 Leader 獲得多數 Server 的支援,則 Server 總數必須是奇 數 2n+1,且存活的 Server 的數目不得少於 n+1。 每個 Server 啟動後都會重複以上流程。在恢復模式下,如果是剛從崩潰狀態恢復的或者剛 啟動的 server 還會從磁碟快照中恢復資料和會話資訊,zk 會記錄事務日誌並定期進行快照, 方便在恢復時進行狀態恢復。 Fast Paxos 流程是在選舉過程中,某 Server 首先向所有 Server 提議自己要成為 leader,當其 它 Server 收到提議以後,解決 epoch 和 zxid 的衝突,並接受對方的提議,然後向對方傳送 接受提議完成的訊息,重複這個流程,最後一定能選舉出 Leader

zookeeper的選主機制:

1、伺服器ID,也就是指我們配置的myid檔案裡面的數字。伺服器ID越大,演算法權重越大,在資料version相同情況下,ID值越大勝出。

2、資料version,每一次資料的更新都會更新此ID,資料ID的值越大說明資料越新,演算法權重越大,在邏輯時鐘相同情況下資料ID越大的勝出。

3、邏輯時鐘,也叫投票的次數,同一輪投票過程中的邏輯時鐘值是相同的。每投完一次票這個資料就會增加,然後與接收到的其它伺服器返回的投票資訊中的數值相比,根據不同的值做出不同的判斷,邏輯時鐘小的選舉結果會被忽略,要求重新投票。

在選舉時節點狀態有以下幾種:

  • LOOKING,競選狀態,也就是當前正處於投票過程中,或者是在叢集節點啟動未過半時,已經啟動的節點會進行投票。
  • FOLLOWING,隨從狀態,同步leader狀態,參與投票。
  • OBSERVING,觀察狀態,同步leader狀態,不參與投票。
  • LEADING,領導者狀態。

舉例說明:

ZooKeeper 的全新叢集選主

  以一個簡單的例子來說明整個選舉的過程:假設有五臺伺服器組成的 zookeeper 叢集,它們 的 serverid 從 1-5,同時它們都是最新啟動的,也就是沒有歷史資料,在存放資料量這一點 上,都是一樣的。假設這些伺服器依序啟動,來看看會發生什麼

  1、伺服器 1 啟動,此時只有它一臺伺服器啟動了,它發出去的報沒有任何響應,所以它的 選舉狀態一直是 LOOKING 狀態

  2、伺服器 2 啟動,它與最開始啟動的伺服器 1 進行通訊,互相交換自己的選舉結果,由於 兩者都沒有歷史資料,所以 id 值較大的伺服器 2 勝出,但是由於沒有達到超過半數以上的伺服器都同意選舉它(這個例子中的半數以上是 3),所以伺服器 1、2 還是繼續保持 LOOKING 狀態

     3、伺服器 3 啟動,根據前面的理論分析,伺服器 3 成為伺服器 1,2,3 中的老大,而與上面不 同的是,此時有三臺伺服器(超過半數)選舉了它,所以它成為了這次選舉的 leader

  4、伺服器 4 啟動,根據前面的分析,理論上伺服器 4 應該是伺服器 1,2,3,4 中最大的,但是 由於前面已經有半數以上的伺服器選舉了伺服器 3,所以它只能接收當小弟的命了

  5、伺服器 5 啟動,同 4 一樣,當小弟

ZooKeeper 的非全新叢集選主

  那麼,初始化的時候,是按照上述的說明進行選舉的,但是當 zookeeper 運行了一段時間之 後,有機器 down 掉,重新選舉時,選舉過程就相對複雜了。

  需要加入資料 version、serverid 和邏輯時鐘。

  資料 version:資料新的 version 就大,資料每次更新都會更新 version

  server id:就是我們配置的 myid 中的值,每個機器一個

  邏輯時鐘:這個值從 0 開始遞增,每次選舉對應一個值,也就是說:如果在同一次選舉中, 那麼這個值應該是一致的;邏輯時鐘值越大,說明這一次選舉 leader 的程序更新,也就是 每次選舉擁有一個 zxid,投票結果只取 zxid 最新的

  選舉的標準就變成:

    1、邏輯時鐘小的選舉結果被忽略,重新投票

    2、統一邏輯時鐘後,資料 version 大的勝出

    3、資料 version 相同的情況下,server id 大的勝出

 根據這個規則選出 leader。