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



6、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


7、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選舉算法:

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

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

3、follower從提議列表中獲取value,如果這個value被大於一半的follower支持,則直接使用此value,否則,繼續發出廣播詢問。並且將此value作為回答其它follower輪訓的提議。

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

paxos的精髓:解決了集群中,非全聯通情況下的一致性問題。對於正常全聯通情況,每台機器只需要廣播獲取其它各台機器的數據,然后比較獲取最大值即可。這樣各個節點得到的結論應該是一樣的。問題在於,某些節點之間是不聯通的。於是某個節點無法獲知全局數據,只能通過paxos中循環投票,收斂至全局最優解。

 

同步流程:選舉完成后,各個follower向leader發送同步請求,帶上自己的最大zxid。leader通過zxid確定同步點,將這之后的commit log交給follower進行同步。所有節點都保存一份系統狀態數據,非強一致(getData不保證最新數據,可以先sync一下保證數據的同步狀態),有同步延時。

 

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