ZooKeeper原理

1、原理概述

          ZooKeeper 的核心是原子廣播機制,這個機制包子了各個server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分別是恢復模式和廣播模式。

 (1) 恢復模式

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

(2) 廣播模式

         一旦Leader已經和多數的Follower進行了狀態同步後,他就可以開始廣播消息了,即進入廣播狀態。這時候當一個Server加入ZooKeeper服務中,它會在恢復模式下啓動,發現Leader,並和Leader進行狀態同步。待到同步結束,它也參與消息廣播。ZooKeeper服務一直維持在Broadcast狀態,直到Leader崩潰了或者Leader失去了大部分的Followers支持。

         Broadcast模式極其類似於分佈式事務中的2pc(two-phrase commit 兩階段提交):即Leader提起一個決議,由Followers進行投票,Leader對投票結果進行計算決定是否通過該決議,如果通過執行該決議(事務),否則什麼也不做。

     在廣播模式ZooKeeper Server會接受Client請求,所有的寫請求都被轉發給領導者,再由領導者將更新廣播給跟隨者。當半數以上的跟隨者已經將修改持久化之後,領導者纔會提交這個更新,然後客戶端纔會收到一個更新成功的響應。這個用來達成共識的協議被設計成具有原子性,因此每個修改要麼成功要麼失敗   

 

2、Zab協議詳解

2、1 廣播模式

      廣播模式類似一個簡單的兩階段提交:Leader發起一個請求,收集選票,並且最終提交,圖3.3演示了我們協議的消息流程。我們可以簡化該兩階段提交協議,因爲我們並沒有"aborts"的情況。followers要麼確認Leader的Propose,要麼丟棄該Leader的Propose。沒有"aborts"意味着,只要有指定數量的機器確認了該Propose,而不是等待所有機器的迴應。

        廣播協議在所有的通訊過程中使用TCP的FIFO信道,通過使用該信道,使保持有序性變得非常的容易。通過FIFO信道,消息被有序的deliver。只要收到的消息一被處理,其順序就會被保存下來。

        Leader會廣播已經被deliver的Proposal消息。在發出一個Proposal消息前,Leader會分配給Proposal一個單調遞增的唯一id,稱之爲zxid。因爲Zab保證了因果有序,所以遞交的消息也會按照zxid進行排序。廣播是把Proposal封裝到消息當中,並添加到指向Follower的輸出隊列中,通過FIFO信道發送到 Follower。當Follower收到一個Proposal時,會將其寫入到磁盤,可以的話進行批量寫入。一旦被寫入到磁盤媒介當中,Follower就會發送一個ACK給Leader。 當Leader收到了指定數量的ACK時,Leader將廣播commit消息並在本地deliver該消息。當收到Leader發來commit消息時,Follower也會遞交該消息。

   需要注意的是, 該簡化的兩階段提交自身並不能解決Leader故障,所以我們 添加恢復模式來解決Leader故障。

2、2 恢復模式

   (1) 恢復階段概述

          正常工作時Zab協議會一直處於廣播模式,直到Leader故障或失去了指定數量的Followers。爲了保證進度,恢復過程中必須選舉出一個新Leader,並且最終讓所有的Server擁有一個正確的狀態。對於Leader選舉,需要一個能夠成功高几率的保證存活的算法。Leader選舉協議,不僅能夠讓一個Leader得知它是leader,並且有指定數量的Follower同意該決定。如果Leader選舉階段發生錯誤,那麼Servers將不會取得進展。最終會發生超時,重新進行Leader選舉。在我們的實現中,Leader選舉有兩種不同的實現方式。如果有指定數量的Server正常運行,快速選舉的完成只需要幾百毫秒。

(2)恢復階段的保證

       該恢復過程的複雜部分是在一個給定的時間內,提議衝突的絕對數量。最大數量衝突提議是一個可配置的選項,但是默認是1000。爲了使該協議能夠即使在Leader故障的情況下也能正常運作。我們需要做出兩條具體的保證:

① 我們絕不能遺忘已經被deliver的消息,若一條消息在一臺機器上被deliver,那麼該消息必須將在每臺機器上deliver。

② 我們必須丟棄已經被skip的消息。

(3) 保證示例

第一條:

       若一條消息在一臺機器上被deliver,那麼該消息必須將在每臺機器上deliver,即使那臺機器故障了。例如,出現了這樣一種情況:Leader發送了commit消息,但在該commit消息到達其他任何機器之前,Leader發生了故障。也就是說,只有Leader自己收到了commit消息。如圖3.4中的C2。

 圖3.4是"第一條保證"(deliver消息不能忘記)的一個示例。在該圖中Server1是一個Leader,我們用L1表示,Server2和Server3爲Follower。首先Leader發起了兩個Proposal,P1和P2,並將P1、P2發送給了Server1和Server2。然後Leader對P1發起了Commit即C1,之後又發起了一個Proposal即P3,再後來又對P2發起了commit即C2,就在此時我們的Leader掛了。那麼這時候,P3和C2這兩個消息只有Leader自己收到了。

  因爲Leader已經deliver了該C2消息,client能夠在消息中看到該事務的結果。所以該事務必須能夠在其他所有的Server中deliver,最終使得client看到了一個一致性的服務視圖。

第二條:

一個被skip的消息,必須仍然需要被skip。例如,發生了這樣一種情況:Leader發送了propose消息,但在該propose消息到達其他任何機器之前,Leader發生了故障。也就是說,只有Leader自己收到了propose消息。如圖3.4中的P3所示。

在圖3.4中沒有任何一個server能夠看到3號提議,所以在圖3.5中當server 1恢復時他需要在系統恢復時丟棄三號提議P3。

          如果Server1 恢復之後再次成爲了Leader,此時再次將P3在P10000001和P10000002之後deliver,那麼將違背順序性的保障。

(4) 保證的實現

      如果Leader選舉協議保證了新Leader在Quorum Server中具有最高的提議編號,即Zxid最高。那麼新選舉出來的leader將具有所有已deliver的消息。新選舉出來的Leader,在提出一個新消息之前,首先要保證事務日誌中的所有消息都由Quorum Follower已Propose並deliver。需要注意的是,我們可以讓新Leader成爲一個用最高zxid來處理事務的server,來作爲一個優化。這樣,作爲新被選舉出來的Leader,就不必去從一組Followers中找出包含最高zxid的Followers和獲取丟失的事務。

① 第一條 

      所有的正確啓動的Servers,將會成爲Leader或者跟隨一個Leader。Leader能夠確保它的Followers看到所有的提議,並deliver所有已經deliver的消息。通過將新連接上的Follower所沒有見過的所有PROPOSAL進行排隊,並之後對該Proposals的COMMIT消息進行排隊,直到最後一個COMMIT消息。在所有這樣的消息已經排好隊之後,Leader將會把Follower加入到廣播列表,以便今後的提議和確認。這一條是爲了保證一致性,因爲如果一條消息P已經在舊Leader-Server1中deliver了,即使它剛剛將消息P deliver之後就掛了,但是當舊Leader-Server1重啓恢復之後,我們的Client就可以從該Server中看到該消息P deliver的事務,所以爲了保證每一個client都能看到一個一致性的視圖,我們需要將該消息在每個Server上deliver。

② 第二條

       skip已經Propose,但不能deliver的消息,處理起來也比較簡單。在我們的實現中,Zxid是由64位數字組成的,低32位用作簡單計數器。高32位是一個epoch。每當新Leader接管它時,將獲取日誌中Zxid最大的epoch,新Leader Zxid的epoch位設置爲epoch+1,counter位設置0。用epoch來標記領導關係的改變,並要求Quorum Servers 通過epoch來識別該leader,避免了多個Leader用同一個Zxid發佈不同的提議。

      這個方案的一個優點就是,我們可以skip一個失敗的領導者的實例,從而加速並簡化了恢復過程。如果一臺宕機的Server重啓,並帶有未發佈的Proposal,那麼先前的未發佈的所有提議將永不會被deliver。並且它不能夠成爲一個新leader,因爲任何一種可能的 Quorum Servers ,都會有一個Server其Proposal 來自與一個新epoch因此它具有一個較高的zxid。當Server以Follower的身份連接,領導者檢查自身最後提交的提議,該提議的epoch 爲Follower的最新提議的epoch(也就是圖3.5中新Leader-Server2中deliver的C2提議),並告訴Follower截斷事務日誌直到該epoch在新Leader中deliver的最後的Proposal即C2。在圖3.5中,當舊Leader-Server1連接到了新leader-Server2,leader將告訴他從事務日誌中清除3號提議P3,具體點就是清除P2之後的所有提議,因爲P2之後的所有提議只有舊Leader-Server1知道,其他Server不知道。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章