1、前言node
在學習了Paxos在Chubby中的應用後,接下來學習Paxos在開源軟件Zookeeper中的應用。算法
2、Zookeeper數據庫
Zookeeper是一個開源的分佈式協調服務,其設計目標是將那些複雜的且容易出錯的分佈式一致性服務封裝起來,構成一個高效可靠的原語集,並以一些列簡單的接口提供給用戶使用。其是一個典型的分佈式數據一致性的解決方案,分佈式應用程序能夠基於它實現諸如數據發佈/發佈、負載均衡、命名服務、分佈式協調/通知、集羣管理、Master選舉、分佈式鎖和分佈式隊列等功能。其能夠保證以下分佈式一致性特性。服務器
① 順序一致性,從同一個客戶端發起的事務請求,最終將會嚴格地按照其發起順序被應用到Zookeeper中去。網絡
② 原子性,全部事務請求的處理結果在整個集羣中全部機器上的應用狀況是一致的,即整個集羣要麼都成功應用了某個事務,要麼都沒有應用。數據結構
③ 單一視圖,不管客戶端鏈接的是哪一個Zookeeper服務器,其看到的服務端數據模型都是一致的。架構
④ 可靠性,一旦服務端成功地應用了一個事務,並完成對客戶端的響應,那麼該事務所引發的服務端狀態變動將會一直被保留,除非有另外一個事務對其進行了變動。併發
⑤ 實時性,Zookeeper保證在必定的時間段內,客戶端最終必定可以從服務端上讀取到最新的數據狀態。負載均衡
2.1 設計目標框架
Zookeeper致力於提供一個高性能、高可用、且具備嚴格的順序訪問控制能力(主要是寫操做的嚴格順序性)的分佈式協調服務,其具備以下的設計目標。
① 簡單的數據模型,Zookeeper使得分佈式程序可以經過一個共享的樹形結構的名字空間來進行相互協調,即Zookeeper服務器內存中的數據模型由一系列被稱爲ZNode的數據節點組成,Zookeeper將全量的數據存儲在內存中,以此來提升服務器吞吐、減小延遲的目的。
② 可構建集羣,一個Zookeeper集羣一般由一組機器構成,組成Zookeeper集羣的而每臺機器都會在內存中維護當前服務器狀態,而且每臺機器之間都相互通訊。
③ 順序訪問,對於來自客戶端的每一個更新請求,Zookeeper都會分配一個全局惟一的遞增編號,這個編號反映了全部事務操做的前後順序。
④ 高性能,Zookeeper將全量數據存儲在內存中,並直接服務於客戶端的全部非事務請求,所以它尤爲適用於以讀操做爲主的應用場景。
2.2 基本概念
① 集羣角色,最典型的集羣就是Master/Slave模式(主備模式),此狀況下把全部可以處理寫操做的機器稱爲Master機器,把全部經過異步複製方式獲取最新數據,並提供讀服務的機器爲Slave機器。Zookeeper引入了Leader、Follower、Observer三種角色,Zookeeper集羣中的全部機器經過Leaser選舉過程來選定一臺被稱爲Leader的機器,Leader服務器爲客戶端提供寫服務,Follower和Observer提供讀服務,可是Observer不參與Leader選舉過程,不參與寫操做的過半寫成功策略,Observer能夠在不影響寫性能的狀況下提高集羣的性能。
② 會話,指客戶端會話,一個客戶端鏈接是指客戶端和服務端之間的一個TCP長鏈接,Zookeeper對外的服務端口默認爲2181,客戶端啓動的時候,首先會與服務器創建一個TCP鏈接,從第一次鏈接創建開始,客戶端會話的生命週期也開始了,經過這個鏈接,客戶端可以心跳檢測與服務器保持有效的會話,也可以向Zookeeper服務器發送請求並接受響應,同時還可以經過該鏈接接受來自服務器的Watch事件通知。
③ 數據節點,第一類指構成集羣的機器,稱爲機器節點,第二類是指數據模型中的數據單元,稱爲數據節點-Znode,Zookeeper將全部數據存儲在內存中,數據模型是一棵樹,由斜槓/進行分割的路徑,就是一個ZNode,如/foo/path1,每一個ZNode都會保存本身的數據內存,同時還會保存一些列屬性信息。ZNode分爲持久節點和臨時節點兩類,持久節點是指一旦這個ZNode被建立了,除非主動進行ZNode的移除操做,不然這個ZNode將一直保存在Zookeeper上,而臨時節點的生命週期和客戶端會話綁定,一旦客戶端會話失效,那麼這個客戶端建立的全部臨時節點都會被移除。另外,Zookeeper還容許用戶爲每一個節點添加一個特殊的屬性:SEQUENTIAL。一旦節點被標記上這個屬性,那麼在這個節點被建立的時候,Zookeeper會自動在其節點後面追加一個整形數字,其是由父節點維護的自增數字。
④ 版本,對於每一個ZNode,Zookeeper都會爲其維護一個叫做Stat的數據結構,Stat記錄了這個ZNode的三個數據版本,分別是version(當前ZNode的版本)、cversion(當前ZNode子節點的版本)、aversion(當前ZNode的ACL版本)。
⑤ Watcher,Zookeeper容許用戶在指定節點上註冊一些Watcher,而且在一些特定事件觸發的時候,Zookeeper服務端會將事件通知到感興趣的客戶端。
⑥ ACL,Zookeeper採用ACL(Access Control Lists)策略來進行權限控制,其定義了以下五種權限:
· CREATE:建立子節點的權限。
· READ:獲取節點數據和子節點列表的權限。
· WRITE:更新節點數據的權限。
· DELETE:刪除子節點的權限。
· ADMIN:設置節點ACL的權限。
2.3 ZAB協議
Zookeeper使用了Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息廣播協議)的協議做爲其數據一致性的核心算法。ZAB協議是爲Zookeeper專門設計的一種支持崩潰恢復的原子廣播協議。
Zookeeper依賴ZAB協議來實現分佈式數據的一致性,基於該協議,Zookeeper實現了一種主備模式的系統架構來保持集羣中各副本之間的數據的一致性,即其使用一個單一的諸進程來接收並處理客戶端的全部事務請求,並採用ZAB的原子廣播協議,將服務器數據的狀態變動以事務Proposal的形式廣播到全部的副本進程中,ZAB協議的主備模型架構保證了同一時刻集羣中只可以有一個主進程來廣播服務器的狀態變動,所以可以很好地處理客戶端大量的併發請求。
ZAB協議的核心是定義了對於那些會改變Zookeeper服務器數據狀態的事務請求的處理方式,即:全部事務請求必須由一個全局惟一的服務器來協調處理,這樣的服務器被稱爲Leader服務器,餘下的服務器則稱爲Follower服務器,Leader服務器負責將一個客戶端事務請求轉化成一個事務Proposal(提議),並將該Proposal分發給集羣中全部的Follower服務器,以後Leader服務器須要等待全部Follower服務器的反饋,一旦超過半數的Follower服務器進行了正確的反饋後,那麼Leader就會再次向全部的Follower服務器分發Commit消息,要求其將前一個Proposal進行提交。
ZAB一些包括兩種基本的模式:崩潰恢復和消息廣播。
當整個服務框架啓動過程當中或Leader服務器出現網絡中斷、崩潰退出與重啓等異常狀況時,ZAB協議就會進入恢復模式並選舉產生新的Leader服務器。當選舉產生了新的Leader服務器,同時集羣中已經有過半的機器與該Leader服務器完成了狀態同步以後,ZAB協議就會退出恢復模式,狀態同步時指數據同步,用來保證集羣在過半的機器可以和Leader服務器的數據狀態保持一致。
當集羣中已經有過半的Follower服務器完成了和Leader服務器的狀態同步,那麼整個服務框架就能夠進入消息廣播模式,當一臺一樣遵照ZAB協議的服務器啓動後加入到集羣中,若是此時集羣中已經存在一個Leader服務器在負責進行消息廣播,那麼加入的服務器就會自覺地進入數據恢復模式:找到Leader所在的服務器,並與其進行數據同步,而後一塊兒參與到消息廣播流程中去。Zookeeper只容許惟一的一個Leader服務器來進行事務請求的處理,Leader服務器在接收到客戶端的事務請求後,會生成對應的事務提議併發起一輪廣播協議,而若是集羣中的其餘機器收到客戶端的事務請求後,那麼這些非Leader服務器會首先將這個事務請求轉發給Leader服務器。
當Leader服務器出現崩潰或者機器重啓、集羣中已經不存在過半的服務器與Leader服務器保持正常通訊時,那麼在從新開始新的一輪的原子廣播事務操做以前,全部進程首先會使用崩潰恢復協議來使彼此到達一致狀態,因而整個ZAB流程就會從消息廣播模式進入到崩潰恢復模式。一個機器要成爲新的Leader,必須得到過半機器的支持,同時因爲每一個機器都有可能會崩潰,所以,ZAB協議運行過程當中,先後會出現多個Leader,而且每臺機器也有可能會屢次成爲Leader,進入崩潰恢復模式後,只要集羣中存在過半的服務器可以彼此進行正常通訊,那麼就能夠產生一個新的Leader並再次進入消息廣播模式。如一個由三臺機器組成的ZAB服務,一般由一個Leader、2個Follower服務器組成,某一個時刻,加入其中一個Follower掛了,整個ZAB集羣是不會中斷服務的。
① 消息廣播,ZAB協議的消息廣播過程使用原子廣播協議,相似於一個二階段提交過程,針對客戶端的事務請求,Leader服務器會爲其生成對應的事務Proposal,並將其發送給集羣中其他全部的機器,而後再分別收集各自的選票,最後進行事務提交。
在ZAB的二階段提交過程當中,移除了中斷邏輯,全部的Follower服務器要麼正常反饋Leader提出的事務Proposal,要麼就拋棄Leader服務器,同時,ZAB協議將二階段提交中的中斷邏輯移除意味着咱們能夠在過半的Follower服務器已經反饋Ack以後就開始提交事務Proposal,而不須要等待集羣中全部的Follower服務器都反饋響應,可是,在這種簡化的二階段提交模型下,沒法處理Leader服務器崩潰退出而帶來的數據不一致問題,所以ZAB採用了崩潰恢復模式來解決此問題,另外,整個消息廣播協議是基於具備FIFO特性的TCP協議來進行網絡通訊的,所以可以很容易保證消息廣播過程當中消息接受與發送的順序性。再整個消息廣播過程當中,Leader服務器會爲每一個事務請求生成對應的Proposal來進行廣播,而且在廣播事務Proposal以前,Leader服務器會首先爲這個事務Proposal分配一個全局單調遞增的惟一ID,稱之爲事務ID(ZXID),因爲ZAB協議須要保證每一個消息嚴格的因果關係,所以必須將每一個事務Proposal按照其ZXID的前後順序來進行排序和處理。
② 崩潰恢復,在Leader服務器出現崩潰,或者因爲網絡緣由致使Leader服務器失去了與過半Follower的聯繫,那麼就會進入崩潰恢復模式,在ZAB協議中,爲了保證程序的正確運行,整個恢復過程結束後須要選舉出一個新的Leader服務器,所以,ZAB協議須要一個高效且可靠的Leader選舉算法,從而保證可以快速地選舉出新的Leader,同時,Leader選舉算法不只僅須要讓Leader自身知道已經被選舉爲Leader,同時還須要讓集羣中的全部其餘機器也可以快速地感知到選舉產生的新的Leader服務器。
③ 基本特性,ZAB協議規定了若是一個事務Proposal在一臺機器上被處理成功,那麼應該在全部的機器上都被處理成功,哪怕機器出現故障崩潰。ZAB協議須要確保那些已經在Leader服務器上提交的事務最終被全部服務器都提交,假設一個事務在Leader服務器上被提交了,而且已經獲得了過半Follower服務器的Ack反饋,可是在它Commit消息發送給全部Follower機器以前,Leader服務掛了。以下圖所示
在集羣正常運行過程當中的某一個時刻,Server1是Leader服務器,其前後廣播了P一、P二、C一、P三、C2(C2是Commit Of Proposal2的縮寫),其中,當Leader服務器發出C2後就當即崩潰退出了,針對這種狀況,ZAB協議就須要確保事務Proposal2最終可以在全部的服務器上都被提交成功,不然將出現不一致。
ZAB協議須要確保丟棄那些只在Leader服務器上被提出的事務。若是在崩潰恢復過程當中出現一個須要被丟棄的提議,那麼在崩潰恢復結束後須要跳過該事務Proposal,以下圖所示
假設初始的Leader服務器Server1在提出一個事務Proposal3以後就崩潰退出了,從而致使集羣中的其餘服務器都沒有收到這個事務Proposal,因而,當Server1恢復過來再次加入到集羣中的時候,ZAB協議須要確保丟棄Proposal3這個事務。
在上述的崩潰恢復過程當中須要處理的特殊狀況,就決定了ZAB協議必須設計這樣的Leader選舉算法:可以確保提交已經被Leader提交的事務的Proposal,同時丟棄已經被跳過的事務Proposal。若是讓Leader選舉算法可以保證新選舉出來的Leader服務器擁有集羣中全部機器最高編號(ZXID最大)的事務Proposal,那麼就能夠保證這個新選舉出來的Leader必定具備全部已經提交的提議,更爲重要的是若是讓具備最高編號事務的Proposal機器稱爲Leader,就能夠省去Leader服務器查詢Proposal的提交和丟棄工做這一步驟了。
④ 數據同步,完成Leader選舉後,在正式開始工做前,Leader服務器首先會確認日誌中的全部Proposal是否都已經被集羣中的過半機器提交了,便是否完成了數據同步。Leader服務器須要確全部的Follower服務器都可以接收到每一條事務Proposal,而且可以正確地將全部已經提交了的事務Proposal應用到內存數據庫中。Leader服務器會爲每一個Follower服務器維護一個隊列,並將那些沒有被各Follower服務器同步的事務以Proposal消息的形式逐個發送給Follower服務器,並在每個Proposal消息後面緊接着再發送一個Commit消息,以表示該事務已經被提交,等到Follower服務器將全部其還沒有同步的事務Proposal都從Leader服務器上同步過來併成功應用到本地數據庫後,Leader服務器就會將該Follower服務器加入到真正的可用Follower列表並開始以後的其餘流程。
下面分析ZAB協議如何處理須要丟棄的事務Proposal的,ZXID是一個64位的數字,其中32位能夠看作是一個簡單的單調遞增的計數器,針對客戶端的每個事務請求,Leader服務器在產生一個新的事務Proposal時,都會對該計數器進行加1操做,而高32位則表明了Leader週期epoch的編號,每當選舉產生一個新的Leader時,就會從這個Leader上取出其本地日誌中最大事務Proposal的ZXID,並解析出epoch值,而後加1,以後以該編號做爲新的epoch,低32位則置爲0來開始生成新的ZXID,ZAB協議經過epoch號來區分Leader週期變化的策略,可以有效地避免不一樣的Leader服務器錯誤地使用不一樣的ZXID編號提出不同的事務Proposal的異常狀況。當一個包含了上一個Leader週期中還沒有提交過的事務Proposal的服務器啓動時,其確定沒法成爲Leader,由於當前集羣中必定包含了一個Quorum(過半)集合,該集合中的機器必定包含了更高epoch的事務的Proposal,所以這臺機器的事務Proposal並不是最高,也就沒法成爲Leader。
2.4 ZAB協議原理
ZAB主要包括消息廣播和崩潰恢復兩個過程,進一步能夠分爲三個階段,分別是發現(Discovery)、同步(Synchronization)、廣播(Broadcast)階段。ZAB的每個分佈式進程會循環執行這三個階段,稱爲主進程週期。
· 發現,選舉產生PL(prospective leader),PL收集Follower epoch(cepoch),根據Follower的反饋,PL產生newepoch(每次選舉產生新Leader的同時產生新epoch)。
· 同步,PL補齊相比Follower多數派缺失的狀態、以後各Follower再補齊相比PL缺失的狀態,PL和Follower完成狀態同步後PL變爲正式Leader(established leader)。
· 廣播,Leader處理客戶端的寫操做,並將狀態變動廣播至Follower,Follower多數派經過以後Leader發起將狀態變動落地(deliver/commit)。
在正常運行過程當中,ZAB協議會一直運行於階段三來反覆進行消息廣播流程,若是出現崩潰或其餘緣由致使Leader缺失,那麼此時ZAB協議會再次進入發現階段,選舉新的Leader。
2.4.1 運行分析
每一個進程都有可能處於以下三種狀態之一
· LOOKING:Leader選舉階段。
· FOLLOWING:Follower服務器和Leader服務器保持同步狀態。
· LEADING:Leader服務器做爲主進程領導狀態。
全部進程初始狀態都是LOOKING狀態,此時不存在Leader,此時,進程會試圖選舉出一個新的Leader,以後,若是進程發現已經選舉出新的Leader了,那麼它就會切換到FOLLOWING狀態,並開始和Leader保持同步,處於FOLLOWING狀態的進程稱爲Follower,LEADING狀態的進程稱爲Leader,當Leader崩潰或放棄領導地位時,其他的Follower進程就會轉換到LOOKING狀態開始新一輪的Leader選舉。
一個Follower只能和一個Leader保持同步,Leader進程和全部與全部的Follower進程之間都經過心跳檢測機制來感知彼此的狀況。若Leader可以在超時時間內正常收到心跳檢測,那麼Follower就會一直與該Leader保持鏈接,而若是在指定時間內Leader沒法從過半的Follower進程那裏接收到心跳檢測,或者TCP鏈接斷開,那麼Leader會放棄當前週期的領導,比你轉換到LOOKING狀態,其餘的Follower也會選擇放棄這個Leader,同時轉換到LOOKING狀態,以後會進行新一輪的Leader選舉,並在選舉產生新的Leader以後開始新的一輪主進程週期。
2.5 ZAB與Paxos的聯繫和區別
聯繫:
① 都存在一個相似於Leader進程的角色,由其負責協調多個Follower進程的運行。
② Leader進程都會等待超過半數的Follower作出正確的反饋後,纔會將一個提議進行提交。
③ 在ZAB協議中,每一個Proposal中都包含了一個epoch值,用來表明當前的Leader週期,在Paxos算法中,一樣存在這樣的一個標識,名字爲Ballot。
區別:
Paxos算法中,新選舉產生的主進程會進行兩個階段的工做,第一階段稱爲讀階段,新的主進程和其餘進程通訊來收集主進程提出的提議,並將它們提交。第二階段稱爲寫階段,當前主進程開始提出本身的提議。
ZAB協議在Paxos基礎上添加了同步階段,此時,新的Leader會確保存在過半的Follower已經提交了以前的Leader週期中的全部事務Proposal。
ZAB協議主要用於構建一個高可用的分佈式數據主備系統,而Paxos算法則用於構建一個分佈式的一致性狀態機系統。
3、總結
此部分也仍是理論知識偏多,學好理論以後再看代碼應該會更快速一些,也謝謝各位園友的觀看~