Zookeeper一致性協議

1、前言

隨著PC機性能的不斷提升和網絡技術的快速普及,很多企業開始放棄原來的大型主機,而改用小型機和普通PC服務器來搭建分布式的計算機系統。其中最為典型的就是阿里巴巴集團的 "去 IOE" 運動。

在以前集中式的應用,我們很容易的能夠實現一套滿足ACID特性的事務處理系統,來保證數據的嚴格一致性。但在分布式的應用中,數據分散在各臺不同的機器上,要想保證數據的嚴格一致性就很難了。因此出現了CAP和BASE這樣的分布式系統經典理論。

1.1、ACID

事務(Transaction)是由一系列對系統中數據進行訪問與更新的操作所組成的一個程序執行邏輯單元(Unit),狹義上的事務特指數據庫事務。

事務包含四大特性,分別是原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)。

1.1.1、原子性

原子性是指事務必須是一個原子的操作序列單元。每一個事務的所有操作要么全部成功,要么全部失敗。

1.1.2、一致性

一致性是指事務的執行不能破環數據庫數據的完整性和一致性。一個事務在執行之前和執行之后,數據庫都必須處于一致性狀態。

1.1.3、隔離性

隔離性是指并發的事務是相互隔離的,一個事務的執行不能被其他事務干擾。

1.1.4、持久性

持久性是指一個事務一旦提交,它對數據庫中對應數據的狀態變更就應該是永久性的。

1.2、CAP定理

CAP定理是指一個分布式系統不可能同時滿足一致性(C:Consistency)、可用性(A:Availability)和分區容錯性(P:Partition tolerance)這三個基本需求,最多只能同時滿足其中的兩項。因為分布式系統中分區容錯性是一定存在的,所以主要還是在一致性和可用性中進行權衡選擇。

cap.jpg
1.2.1、一致性

在分布式環境中,一致性是指數據在多個副本之間是否能夠保持一致的特性。在一致性的需求下,當一個系統在數據一致的狀態下執行更新操作后,應該保證系統的數據仍然處于一致的狀態。

對于一個將數據副本分布在不同分布式節點上的系統來說,如果對第一個節點的數據進行了更新操作并且更新成功后,卻沒有使得第二個節點上的數據得到相應的更新,于是在對第二個節點的數據進行讀取操作時,獲取的依然是老數據(或稱為臟數據),這就是典型的分布式數據不一致情況。在分布式系統中,如果能夠做到針對一個數據項的更新操作執行成功后,所有的用戶都可以讀取到其最新的值,那么這樣的系統就被認為具有強一致性(或嚴格的一致性)。

1.2.2、可用性

可用性是指系統提供的服務必須一直處于可用的狀態,對于用戶的每一個操作請求總是能夠在有限的時間內返回結果。

1.2.3、分區容錯性

分區容錯性約束了一個分布式系統需要具有如下特性:分布式系統在遇到任何網絡分區故障的時候,仍然需要能夠保證對外提供滿足一致性和可用性的服務,除非是整個網絡環境都發生了故障。

網絡分區是指在分布式系統中,不同的節點分布在不同的子網絡(機房或異地網絡等)中,由于一些特殊的原因導致這些子網絡之間出現網絡不連通的狀況,但各個子網絡的內部網絡是正常的,從而導致整個系統的網絡環境被切分成了若干個孤立的區域。需要注意的是,組成一個分布式系統的每個節點的加入與退出都可以看作是一個特殊的網絡分區。

1.3、BASE理論

BASE理論是指 Basically Available(基本可用)、Soft state(軟狀態)和 Eventually consistent(最終一致性)三個短語的簡寫。是對 CAP 中一致性和可用性權衡的結果。是基于 CAP 定理逐步演化而來的,其核心思想是即使無法做到強一致性,但每個應用都可以根據自身的業務特點,采用適當的方式來使系統達到最終一致性。

1.3.1、基本可用

基本可用是指分布式系統在出現不可預知故障的時候,允許損失部分可用性——但請注意,這絕不等價于系統不可用。

1.3.2、弱狀態

弱狀態也稱為軟狀態,和硬狀態相對,是指允許系統中的數據存在中間狀態,并認為該中間狀態的存在不會影響系統的整體可用性,即允許系統在不同節點的數據副本之間進行數據同步的過程存在延時。

1.3.3、最終一致性

最終一致性強調的是系統中所有的數據副本,在經過一段時間的同步后,最終能夠達到一個一致的狀態。因此,最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性。

2、一致性協議和算法

為了解決分布式一致性問題,在長期的探索研究過程中,涌現出了一大批經典的一致性協議和算法,其中最著名的就是二階段提交協議、三階段提交協議和Paxos算法。

2.1、2PC協議

2PC,是 Two-Phase Commit 的縮寫,即二階段提交,是計算機網絡尤其是在數據庫領域內,為了使基于分布式系統架構下的所有節點在進行事務處理過程中能夠保持原子性和一致性而設計的一種算法。

2.1.1、協議說明

二階段提交協議是將事務的提交過程分成了兩個階段來進行處理。在講述流程之前先介紹兩個概念:

  • 協調者: 用來統一調度所有分布式節點的執行邏輯。

  • 參與者: 被調度的分布式節點。

其執行流程如下:

  • 階段一:提交事務請求(投票階段)

    1. 分發事務

      協調者向所有的參與者發送事務內容,詢問是否可以執行事務提交操作,并開始等待各參與者的響應。

    2. 執行事務

      各參與者節點執行事務操作,并將Undo 和 Redo 信息記入事務日志中。

    3. 反饋響應

      如果參與者成功執行了事務操作,那么就反饋給協調者 Yes 響應,表示事務可以執行;

      如果參與者沒有成功執行事務,那么就反饋給協調者 No 響應,表示事務不可以執行。

  • 階段二:執行事務請求(執行階段)

    協調者根據各參與者的反饋情況來決定最終是否可以進行事務提交操作,正常情況下,包含以下兩種可能。

    提交事務

    ? 假如協調者從所有的參與者獲得的反饋都是 Yes 響應,那么就會執行事務提交。

    1. 發送提交請求

      協調者向所有參與者節點發出 Commit 請求。

    2. 事務提交

      參與者接收到 Commit 請求后,會正式執行事務提交操作,并在完成提交之后釋放在整個事務執行期間占用的事務資源。

    3. 反饋事務提交結果

      參與者在完成事務提交之后,向協調者發送Ack消息。

    4. 完成事務

      協調者接收到所有參與者反饋的 Ack 消息后,完成事務。

    中斷事務

    ? 假如任何一個參與者向協調者反饋了 No 響應,或者在等待超時之后,協調者尚無法接收到所有參與者的反饋響應,那么就會中斷事務。

    1. 發送回滾請求

      協調者向所有參與者節點發出 Rollback 請求。

    2. 事務回滾

      參與者接收到 Rollback 請求后,會利用其在階段一中記錄的 Undo 信息來執行事務回滾操作,并在完成回滾之后釋放在整個事務執行期間占用的資源。

    3. 反饋事務回滾結果

      參與者在完成事務回滾之后,向協調者發送 Ack 消息。

    4. 中斷事務

      協調者接收到所有參與者反饋的 Ack 消息后,完成事務中斷。

2.1.2、優缺點

優點:

  • 原理簡單
  • 實現方便

缺點:

  • 同步阻塞

    二階段提交協議存在的最明顯也是最大的一個問題就是同步阻塞,這會極大地限制分布式系統的性能。在二階段提交的執行過程中,所有參與該事務操作的邏輯都處于阻塞狀態,也就是說,各個參與者在等待其他參與者響應的過程中,將無法進行其他任何操作。

  • 單點問題

    在二階段提交中,一旦協調者出現問題,那么整個二階段提交流程將無法運轉,更為嚴重的是,如果協調者是在階段二中出現問題的話,那么其他參與者將會一直處于鎖定事務資源的狀態中,而無法繼續完成事務操作。

  • 數據不一致

    在二階段提交協議的階段二,即執行事務提交的時候,當協調者向所有的參與者發送Commit 請求之后,發生了局部網絡異常或者是協調者在尚未發送完 Commit 請求之前自身發生了崩潰,導致最終只有部分參與者收到了 Commit 請求。于是,這部分收到了 Commit 請求的參與者就會進行事務的提交,而其他沒有收到 Commit 請求的參與者則無法進行事務提交,于是整個分布式系統便出現了數據不一致性現象。

  • 太過保守

    二階段提交協議沒有設計較為完善的容錯機制,任意一個節點的失敗都會導致整個事務的失敗。

2.2、3PC協議

2.2.1、協議說明

3PC,是 Three-Phase Commit 的縮寫,即三階段提交,是 2PC 的改進版,其將二階段提交協議的“提交事務請求”過程一分為二,形成了由 CanCommit、PreCommit 和 DoCommit 三個階段組成的事務處理協議。其執行流程如下:

  • 階段一:CanCommit

    1. 事務詢問

      協調者向所有的參與者發送一個包含事務內容的 CanCommit 請求,詢問是否可以執行事務提交操作,并開始等待各參與者的響應。

    2. 反饋響應

      參與者在接收到來自協調者的 CanCommit 請求后,正常情況下,如果其自身認為可以順利執行事務,那么會反饋 Yes 響應,并進入預備狀態,否則反饋 No 響應。

  • 階段二:PreCommit

    協調者會根據各參與者的反饋情況來決定是否可以進行事務的 PreCommit 操作,正常情況下,包含兩種可能。

    執行事務預提交

    ? 假如協調者從所有的參與者獲得的反饋都是 Yes 響應,那么就會執行事務預提交。

    1. 發送預提交請求

      協調者向所有參與者節點發出 PreCommit 的請求,并進入 Prepared 階段。

    2. 事務預提交

      參與者接收到 PreCommit 請求后,會執行事務操作,并將 Undo 和 Redo 信息記錄到事務日志中。

    3. 反饋響應

      如果參與者成功執行了事務操作,那么就會反饋給協調者 Ack 響應,同時等待最終的指令:提交 (commit)或中止(abort)。

    中斷事務

    ? 假如任何一個參與者向協調者反饋了No 響應,或者在等待超時之后,協調者尚無法接收到所有參與者的反饋響應,那么就會中斷事務。

    1. 發送中斷請求

      協調者向所有參與者節點發出 abort 請求。

    2. 中斷事務

      無論是收到來自協調者的 abort 請求,或者是在等待協調者請求過程中出現超時,參與者都會中斷事務。

  • 階段三:DoCommit

    該階段將進行真正的事務提交,會存在以下兩種可能的情況。

    執行提交

    1. 發送提交請求

      進入這一階段,假設協調者處于正常工作狀態,并且它接收到了來自所有參與者的 Ack 響應,那么它將從 “預提交” 狀態轉換到 “提交” 狀態,并向所有的參與者發送 doCommit 請求。

    2. 事務提交

      參與者接收到 doCommit 請求后,會正式執行事務提交操作,并在完成提交之后釋放在整個事務執行期間占用的事務資源。

    3. 反饋事務提交結果

      參與者在完成事務提交之后,向協調者發送 Ack 消息。

    4. 完成事務

      協調者接收到所有參與者反饋的 Ack 消息后,完成事務。

    中斷事務

    ? 進入這一階段,假設協調者處于正常工作狀態,并且有任意一個參與者向協調者反饋了No 響應,或者在等待超時之后,協調者尚無法接收到所有參與者的反饋響應,那么就會中斷事務。

    1. 發送中斷請求

      協調者向所有的參與者節點發送 abort 請求。

    2. 事務回滾

      參與者接收到 abort 請求后,會利用其在階段二中記錄的 Undo 信息來執行事務回滾操作,并在完成回滾之后釋放在整個事務執行期間占用的資源。

    3. 反饋事務回滾結果

      參與者在完成事務回滾之后,向協調者發送 Ack 消息。

    4. 中斷事務

      協調者接收到所有參與者反饋的 Ack 消息后,中斷事務。

    注意:階段三可能會存在以下兩種故障

    • 協調者出現問題。
    • 協調者和參與者之間的網絡出現故障。

    無論出現哪種情況,最終都會導致參與者無法及時接收到來自協調者的 doCommit 或是 abort 請求,針對這樣的異常情況,參與者都會在等待超時之后,繼續進行事務提交。

2.2.2、優缺點

優點:

  • 相較于二階段提交,三階段提交降低了參與者的阻塞范圍。
  • 能夠在出現單點故障后繼續達成一致。

缺點:

  • 數據不一致

    在參與者接收到 preCommit 消息后,如果網絡出現分區,此時協調者所在的節點和參與者無法進行正常的網絡通信,在這種情況下,該參與者依然會進行事務的提交,這必然出現數據的不一致性。

2.3、Paxos算法

Paxos 算法是一種基于消息傳遞且具有高度容錯特性的一致性算法。是目前公認的解決分布式一致性問題最有效的算法之一。(這里不介紹Paxos算法,后面會寫一篇文章專題講講Paxos算法)

3、ZAB(Zookeeper Atomic Broadcast)協議

ZAB協議是為分布式協調服務Zookeeper專門設計的一種支持崩潰恢復的原子廣播協議。基于該協議,Zookeeper實現了一種主備模式的系統架構來保持集群中各副本之間數據的一致性。

3.1、核心處理過程

所有事務請求必須由一個全局唯一的服務器來協調處理,這樣的服務器被稱為 Leader 服務器,而余下的其他服務器則成為 Follower 服務器。 Leader 服務器負責將一個客戶端事務請求轉換成一個事務 Proposal(提議),并將該 Proposal 分發給集群中所有的 Follower 服務器。之后 Leader 服務器需要等待所有 Follower 服務器的反饋,一旦超過半數的 Follower 服務器進行了正確的反饋后,那么 Leader 就會再次向所有的 Follower 服務器分發 Commit 消息,要求其將前一個 Proposal 進行提交。

3.2、協議介紹

ZAB協議包括兩種基本的模式,分別是崩潰恢復和消息廣播。當整個服務框架在啟動過程中,或是當 Leader 服務器出現網絡中斷,崩潰退出與重啟等異常情況時,ZAB 協議就會進入恢復模式并選舉產生新的 Leader 服務器。當選舉產生了新的 Leader 服務器,同時集群中已經有過半的機器與該 Leader 服務器完成了狀態同步(數據同步)之后,ZAB 協議就會退出恢復模式,進入消息廣播模式。Leader 服務器在接收到客戶端的事務請求后,會生成對應的事務提案并發起一輪廣播協議;而如果集群中的其他機器接收到客戶端的寫事務請求,那么這些非 Leader 服務器會首先將這個事務請求轉發給 Leader 服務器。
如果新加入了一臺服務器,此服務器就會進入數據恢復模式,找到Leader 所在的服務器,并與其進行數據同步,然后一起參與到消息廣播流程中去。

3.2.1、崩潰恢復模式

當整個服務器框架啟動過程中,或是當 Leader 服務器出現崩潰,或者說由于網絡原因導致 Leader 服務器失去了與過半 Follower 的聯系,那么就會進入崩潰恢復模式。(說白了崩潰恢復模式就是選舉新的 Leader,完成數據同步)

在崩潰恢復過程中可能會出現兩個數據不一致性的問題:

  • ZAB 協議需要確保那些已經在 Leader服務器上提交的事務最終被所有服務器都提交。

    假設一個事務在 Leader 服務器上被提交了,并且已經得到過半的 Follower 服務器的 Ack 反饋,但是在它將 Commit 消息發送給所有 Follower 機器之前,Leader 服務器掛了。針對這種情況, ZAB 協議就需要確保事務最終能夠在所有的服務器上都被提交成功,否則將出現不一致。

  • ZAB 協議需要確保丟棄那些只在 Leader 服務器上被提出的事務

    假設在 Leader 服務器上 Server1 提出了一個事務之后就崩潰退出了,從而導致集群中的其他服務器都沒有收到這個事務。于是,當 Server1 恢復過來再次加入到集群中的時候,ZAB 協議需要確保丟棄這個事務。

對于上面提出的問題,決定了 ZAB 協議必須設計這樣一個 Leader 選舉算法:能夠確保提交已經被 Leader 提交的事務 Proposal,同時丟棄已經被跳過的事務 Proposal。針對這個要求,如果讓 Leader 選舉算法能夠保證新選舉出來的 Leader 服務器擁有集群中所有機器最高編號(即 ZXID 最大)的事務 Proposal,那么就可以保證這個新選舉出來的 Leader 一定具有所有已經提交的提案。更為重要的是如果讓具有最高編號事務 Proposal 的機器來成為 Leader ,就可以省去 Leader 服務器檢查 Proposal 的提交和丟棄工作的這一步操作了。(Leader選舉過程請看 《Zookeeper深入原理》)

在完成 Leader 選舉之后,正式開始工作之前,還需要確認事務日志中的所有 Proposal 是否都已經被集群中過半的機器提交了,即是否完成了數據同步。

下面介紹一下數據同步過程:

Leader服務器會為每一個 Follower服務器都準備一個隊列,并將那些沒有被各 Follower 服務器同步的事務以 Proposal 消息的形式逐個發送給 Follower 服務器,并在每一個 Proposal 消息后面緊接著再發送一個 Commit 消息,以表示該事務已經被提交。等到 Follower 服務器將所有其尚未同步的事務 Proposal 都從 Leader 服務器上同步過來并成功應用到本地數據庫中后,Leader 服務器就會將該 Follower 服務器加入到真正的可用 Follower 列表中。

3.2.2、消息廣播模式

ZAB 協議的消息廣播過程使用的是一個原子廣播協議,類似于一個二階段提交的過程。但是 ZAB 協議與二階段提交略有不同。在 ZAB 協議的二階段提交過程中,移除了中斷邏輯,所有的 Follower 服務器要么正常反饋 Leader 提出的事務 Proposal,要么就拋棄 Leader 服務器。同時 ZAB 協議支持半數原則,即超過半數的 Follower 服務器反饋 Ack 之后就開始提交事務 Proposal 了,而不需要等待集群中所有的 Follower 服務器都反饋響應。

因為這種簡化的二階段提交模型下,是無法處理 Leader 服務器崩潰退出而帶來的數據不一致問題的,因此在ZAB 協議中添加了崩潰恢復模式來解決這種問題。

在消息廣播過程中,Leader 服務器會為每一個事務請求生成對應的 Proposal 來進行廣播,并且在廣播事務 Proposal 之前,Leader 服務器會首先為這個事務 Proposal 分配一個全局單調遞增的唯一ID(即 ZXID),Leader服務器會為每一個 Follower 服務器都各自分配一個單獨的隊列,然后將需要廣播的事務 Proposal 依次放入這些隊列中去,并且根據 FIFO 策略進行消息發送。每一個 Follower 服務器在接收到這個事務 Proposal 之后,都會首先將其以事務日志的形式寫入到本地磁盤中去,并且在成功寫入后反饋給 Leader 服務器一個 Ack 響應。當 Leader 服務器接收到超過半數 Follower 的 Ack 響應后,就會廣播一個 Commit 消息給所有的 Follower 服務器以通知其進行事務提交,同時 Leader 自身也會完成對事務的提交,而每一個 Follower 服務器在接收到 Commit 消息后,也會完成對事務的提交。

3.3、協議說明

整個 ZAB 協議主要包括消息廣播和崩潰恢復兩個過程,進一步可以細分為三個階段,分別是發現(Discovery)、同步(Synchronization)和廣播(Broadcast)階段。

階段一:發現

主要就是 Leader 選舉過程,用于在多個分布式進程中選舉出主進程。

階段二:同步

在完成發現流程之后,就進入了同步階段。即 Leader 服務器和 Follower 服務器之間同步數據。

階段三:廣播

完成同步階段之后,ZAB 協議就可以正式開始接收客戶端新的事物請求,并進行消息廣播流程。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容