zookeeper是hadoop下面的一個子項目, 用來協調跟hadoop相關的一些分佈式的框架, 如hadoop, hive, pig等, 其實他們都是動物, 因此叫zookeeper(本人歪歪).

zookeeper實際上是集羣中每一個節點都維護着一棵相同的樹, 樹的結構跟linux的目錄結構的概念差很少, 以/爲跟節點, 下邊能夠擴展任意的節點和葉子節點, 每一個節點均可以寫入數據. 基於zookeeper的分佈式鎖的實現, 實際上是得益於zookeeper同步文件的強大性, 咱們相信每時每刻咱們訪問zookeeper的樹時, 相同節點返回的數據都是一致的. 這要靠zookeeper內部的一些算法來實現. 特別是leader的選舉算法, 這裏就不說了, 感興趣的話能夠去搜索一下看看.

咱們知道了zookeeper集羣的每一個節點的數據都是一致的, 那麼咱們能夠經過這些節點來做爲鎖的標誌.

首先給鎖設置一下API, 至少要包含, lock(鎖住), unlock(解鎖), isLocked(是否鎖住)三個方法

而後咱們能夠建立一個工廠(LockFactory), 用來專門生產鎖.

鎖的建立過程以下描述:

前提:每一個鎖都須要一個路徑來指定(如:/jiacheo/lock)

1.根據指定的路徑, 查找zookeeper集羣下的這個節點是否存在.(說明已經有鎖了)

2. 若是存在, 根據查詢者的一些特徵數據(如ip地址/hostname), 當前的鎖是否是查詢者的

3. 若是不是查詢者的鎖, 則返回null, 說明建立鎖失敗

4. 若是是查詢者的鎖, 則把這個鎖返回給查詢者

5. 若是這個節點不存在, 說明當前沒有鎖, 那麼建立一個臨時節點, 並將查詢者的特徵信息寫入這個節點的數據中, 而後返回這個鎖.

根據以上5部, 一個分佈式的鎖就能夠建立了.

建立的鎖有三種狀態:

1. 建立失敗(null), 說明該鎖被其餘查詢者使用了.’

2. 建立成功, 但當前沒有鎖住(unlocked), 可使用

3. 建立成功, 但當前已經鎖住(locked)了, 不能繼續加鎖.

如圖, 若是咱們getLock(「/jiacheo/lock1″,」192.168.0.100″), 想要獲取/jiacheo/lock1這個鎖的話, 咱們先判斷這個節點是否存在, 存在的話獲取他的數據(data), 而後經過解析data, 咱們能夠知道這個節點是否是咱們查詢者建立的(經過ip地址寫入節點數據中), 而後就能夠返回一個鎖了.

正確實現一個分佈式鎖是一件很是棘手的事情,由於很難對全部類型的故障進行正確的處理,ZooKeeper帶有一個Java語言編寫的生產級別的鎖實現,名爲WriteLock,客戶端能夠方便的使用它。

(b)zookeeper分佈式鎖

    link:http://www.searchtb.com/2011/01/zookeeper-research.html

 

        擁有了zookeeper如此強大的分佈式協做系統後,咱們能夠很容易的實現大量的分佈式應用,包括了分佈式鎖,分佈式隊列,分佈式Barrier,雙階段提交等等. 這些應用能夠幫咱們改進不少複雜系統的協做方式,將這些系統的實現變得更加優雅而高效.鑑於篇幅,本文僅介紹分佈式鎖的實現.
利用了前文提到的sequence nodes能夠很是容易的實現分佈式鎖. 實現分佈式鎖的基本步驟以下(這些步驟須要在全部須要鎖的客戶端執行):

  1. client調用create()建立名爲」_locknode_/lock-」的節點,注意須要設置sequence和ephemeral屬性
  2. client調用getChildren(「_locknode_」),注意不能設置watch,這樣才能避免羊羣效應
  3. 若是步驟1中建立的節點序號最低,則該client得到鎖,開始執行其它程序
  4. client對lock-xxx中序號僅次於本身建立節點的那個節點調用exists(),並設置watch
  5. 若是exist()返回false(節點不存在)則回到步驟2,不然等待步驟4中的watch被觸發並返回步驟2

分佈式鎖在zookeeper的源代碼中已經有實現,能夠參考org.apache.zookeeper.recipes.lock



六、ZooKeeper一致性協議-Zab

 

link:http://blog.csdn.net/chen77716/article/details/7309915

Zookeeper的一致性協議:Zab

分類: 分佈式算法   2657人閱讀  評論(3)  收藏  舉報
 

目錄(?)[+]

 

      Zookeeper使用了一種稱爲Zab(Zookeeper Atomic Broadcast)的協議做爲其一致性複製的核心,據其做者說這是一種新發算法,其特色是充分考慮了Yahoo的具體狀況:高吞吐量、低延遲、健壯、簡單,但不過度要求其擴展性。下面將展現一些該協議的核心內容:

另,本文僅討論Zookeeper使用的一致性協議而非討論其源碼實現

        Zookeeper的實現是有Client、Server構成,Server端提供了一個一致性複製、存儲服務,Client端會提供一些具體的語義,好比分佈式鎖、選舉算法、分佈式互斥等。從存儲內容來講,Server端更多的是存儲一些數據的狀態,而非數據內容自己,所以Zookeeper能夠做爲一個小文件系統使用。數據狀態的存儲量相對不大,徹底能夠所有加載到內存中,從而極大地消除了通訊延遲。

        Server能夠Crash後重啓,考慮到容錯性,Server必須「記住」以前的數據狀態,所以數據須要持久化,但吞吐量很高時,磁盤的IO便成爲系統瓶頸,其解決辦法是使用緩存,把隨機寫變爲連續寫。

考慮到Zookeeper主要操做數據的狀態,爲了保證狀態的一致性,Zookeeper提出了兩個安全屬性(Safety Property)

 

  • 全序(Total order):若是消息a在消息b以前發送,則全部Server應該看到相同的結果
  • 因果順序(Causal order):若是消息a在消息b以前發生(a致使了b),並被一塊兒發送,則a始終在b以前被執行。
爲了保證上述兩個安全屬性,Zookeeper使用了TCP協議和Leader。經過使用TCP協議保證了消息的全序特性(先發先到),經過Leader解決了因果順序問題:先到Leader的先執行。由於有了Leader,Zookeeper的架構就變爲:Master-Slave模式,但在該模式中Master(Leader)會Crash,所以,Zookeeper引入了Leader選舉算法,以保證系統的健壯性。概括起來Zookeeper整個工做分兩個階段:
  • Atomic Broadcast
  • Leader選舉

1. Atomic Broadcast

同一時刻存在一個Leader節點,其餘節點稱爲「Follower」,若是是更新請求,若是客戶端鏈接到Leader節點,則由Leader節點執行其請求;若是鏈接到Follower節點,則需轉發請求到Leader節點執行。但對讀請求,Client能夠直接從Follower上讀取數據,若是須要讀到最新數據,則須要從Leader節點進行,Zookeeper設計的讀寫比例是2:1。
 
Leader經過一個簡化版的二段提交模式向其餘Follower發送請求,但與二段提交有兩個明顯的不一樣之處:
  • 由於只有一個Leader,Leader提交到Follower的請求必定會被接受(沒有其餘Leader干擾)
  • 不須要全部的Follower都響應成功,只要一個多數派便可
通俗地說,若是有2f+1個節點,容許f個節點失敗。由於任何兩個多數派必有一個交集,當Leader切換時,經過這些交集節點能夠得到當前系統的最新狀態。若是沒有一個多數派存在(存活節點數小於f+1)則,算法過程結束。但有一個特例:
若是有A、B、C三個節點,A是Leader,若是B Crash,則A、C能正常工做,由於A是Leader,A、C還構成多數派;若是A Crash則沒法繼續工做,由於Leader選舉的多數派沒法構成。

2. Leader Election

Leader選舉主要是依賴Paxos算法,具體算法過程請參考其餘博文,這裏僅考慮Leader選舉帶來的一些問題。Leader選舉遇到的最大問題是,」新老交互「的問題,新Leader是否要繼續老Leader的狀態。這裏要按老Leader Crash的時機點分幾種狀況:
  1. 老Leader在COMMIT前Crash(已經提交到本地)
  2. 老Leader在COMMIT後Crash,但有部分Follower接收到了Commit請求
第一種狀況,這些數據只有老Leader本身知道,當老Leader重啓後,須要與新Leader同步並把這些數據從本地刪除,以維持狀態一致。
第二種狀況,新Leader應該能經過一個多數派得到老Leader提交的最新數據
老Leader重啓後,可能還會認爲本身是Leader,可能會繼續發送未完成的請求,從而由於兩個Leader同時存在致使算法過程失敗,解決辦法是把Leader信息加入每條消息的id中,Zookeeper中稱爲zxid,zxid爲一64位數字,高32位爲leader信息又稱爲epoch,每次leader轉換時遞增;低32位爲消息編號,Leader轉換時應該從0從新開始編號。經過zxid,Follower能很容易發現請求是否來自老Leader,從而拒絕老Leader的請求。
 
由於在老Leader中存在着數據刪除(狀況1),所以Zookeeper的數據存儲要支持補償操做,這也就須要像數據庫同樣記錄log。

3. Zab與Paxos

Zab的做者認爲Zab與paxos並不相同,只因此沒有采用Paxos是由於Paxos保證不了全序順序:
Because multiple leaders can
propose a value for a given instance two problems arise.
First, proposals can conflict. Paxos uses ballots to detect and resolve conflicting proposals. 
Second, it is not enough to know that a given instance number has been committed, processes must also be able to figure out which value has been committed.
Paxos算法的確是不關係請求之間的邏輯順序,而只考慮數據之間的全序,但不多有人直接使用paxos算法,都會通過必定的簡化、優化。
通常Paxos都會有幾種簡化形式,其中之一即是,在存在Leader的狀況下,能夠簡化爲1個階段(Phase2)。僅有一個階段的場景須要有一個健壯的Leader,所以工做重點就變爲Leader選舉,在考慮到Learner的過程,還須要一個」學習「的階段,經過這種方式,Paxos可簡化爲兩個階段:
  • 以前的Phase2
  • Learn
若是再考慮多數派要Learn成功,這其實就是Zab協議。Paxos算法着重是強調了選舉過程的控制,對決議學習考慮的很少,Zab剛好對此進行了補充。
以前有人說,全部分佈式算法都是Paxos的簡化形式,雖然很絕對,但對不少狀況的確如此,但不知Zab的做者是否定同這種說法?

4.結束

本文只是想從協議、算法的角度分析Zookeeper,而非分析其源碼實現,由於Zookeeper版本的變化,文中描述的場景或許已找不到對應的實現。另,本文還試圖揭露一個事實:Zab就是Paxos的一種簡化形式。
【參考資料】
  • A simple totally ordered broadcast protocol
  • paxos


七、ZooKeeper選舉和同步
 

zookeeper

  301人閱讀  評論(0)  收藏  舉報

http://stblog.baidu-tech.com/?p=1164

 

用於分佈式下一致性相關問題的解決方案。能夠理解爲由集羣組成的可靠的單master。可將傳統方案中的master使用zookeeper代替,且不用擔憂單點問題。

 

應用場景:樹狀結構的命名服務、節點數據變動的消息通知、分佈式共享鎖、配置數據的集中存放、集羣中節點機器的狀態管理及狀態變動通知

zookeeper實現分佈式鎖:經過zookeeper的節點狀態進行條件判斷,若是不知足,則在客戶端本地加鎖等待Object.wait()。利用zookeeper的實時通知機制,當zookeeper的節點知足條件狀態時,客戶端會同步得到通知,而後在本地解鎖Object.notifyAll()。從而實現了分佈式加鎖、阻塞、解鎖。

 

三類角色: leader(處理寫請求,單點)、follower(處理客戶端請求,參與投票)、observer(不投票,只處理客戶端請求)

恢復模式:服務重啓或者leader宕機後,經過paxos算法,從follower中從新選出leader,並以leader爲準,進行數據同步。此時服務不可用。

 

paxos選舉算法:

一、每次選舉,都是針對某個txid(transaction id)進行。

二、每一個follower首先廣播詢問,獲取其它全部server的txid、提議value,txid必須相同,value存儲到提議列表中

三、follower從提議列表中獲取value,若是這個value被大於一半的follower支持,則直接使用此value,不然,繼續發出廣播詢問。而且將此value做爲回答其它follower輪訓的提議。

四、循環執行3,直到收斂

paxos的精髓:解決了集羣中,非全聯通狀況下的一致性問題。對於正常全聯通狀況,每臺機器只須要廣播獲取其它各臺機器的數據,而後比較獲取最大值便可。這樣各個節點獲得的結論應該是同樣的。問題在於,某些節點之間是不聯通的。因而某個節點沒法獲知全局數據,只能經過paxos中循環投票,收斂至全局最優解。

 

同步流程:選舉完成後,各個follower向leader發送同步請求,帶上本身的最大zxid。leader經過zxid肯定同步點,將這以後的commit log交給follower進行同步。全部節點都保存一份系統狀態數據,非強一致(getData不保證最新數據,能夠先sync一下保證數據的同步狀態),有同步延時。

 

多節點可讀可寫,部分節點延時同步,最終一致性。follower和observer負責監聽客戶請求和處理讀請求。對於全部寫請求,都一概轉發至leader進行選舉和數據同步。observer不參與投票,只作數據同步,提升寫請求的效率。