1. 程式人生 > >【轉】淺談分布式服務協調技術 Zookeeper

【轉】淺談分布式服務協調技術 Zookeeper

客戶 內存數據 訂閱 數據開發 watcher database 所有 ren info

非常好介紹Zookeeper的文章,

Google的三篇論文影響了很多很多人,也影響了很多很多系統。這三篇論文一直是分布式領域傳閱的經典。根據MapReduce,於是我們有了Hadoop;根據GFS,於是我們有了HDFS;根據BigTable,於是我們有了HBase。而在這三篇論文裏都提及Google的一個Lock Service —— Chubby,哦,於是我們有了Zookeeper。

隨著大數據的火熱,Hxx們已經變得耳熟能詳,現在作為一個開發人員如果都不知道這幾個名詞出門都好像不好意思跟人打招呼。但實際上對我們這些非大數據開發人員而言,Zookeeper是比Hxx們可能接觸到更多的一個基礎服務。但是,無奈的是它一直默默的位於二線,從來沒有Hxx們那麽耀眼。那麽到底什麽是Zookeeper呢?Zookeeper可以用來幹什麽?我們將如何使用Zookeeper?Zookeeper又是怎麽實現的?

什麽是Zookeeper

在Zookeeper的官網上有這麽一句話:ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services。

這大概描述了Zookeeper主要是一個分布式服務協調框架,實現同步服務,配置維護和命名服務等分布式應用。是一個高性能的分布式數據一致性解決方案。

通俗地講,ZooKeeper是動物園管理員,它是拿來管大象 Hadoop、鯨魚 HBase、Kafka等的管理員。

Zookeeper和CAP的關系

作為一個分布式系統,分區容錯性是一個必須要考慮的關鍵點。一個分布式系統一旦喪失了分區容錯性,也就表示放棄了擴展性。因為在分布式系統中,網絡故障是經常出現的,一旦出現在這種問題就會導致整個系統不可用是絕對不能容忍的。所以,大部分分布式系統都會在保證分區容錯性的前提下在一致性和可用性之間做權衡。

技術分享

ZooKeeper是個CP(一致性+分區容錯性)的,即任何時刻對ZooKeeper的訪問請求能得到一致的數據結果,同時系統對網絡分割具備容錯性;但是它不能保證每次服務請求的可用性。也就是在極端環境下,ZooKeeper可能會丟棄一些請求,消費者程序需要重新請求才能獲得結果。

ZooKeeper是分布式協調服務,它的職責是保證數據在其管轄下的所有服務之間保持同步、一致;所以就不難理解為什麽ZooKeeper被設計成CP而不是AP特性的了。而且, 作為ZooKeeper的核心實現算法Zab,就是解決了分布式系統下數據如何在多個服務之間保持同步問題的。

Zookeeper節點特性及節點屬性分析

Zookeeper提供基於類似於文件系統的目錄節點樹方式的數據存儲,但是Zookeeper並不是用來專門存儲數據的,它的作用主要是用來維護和監控你存儲的數據的狀態變化。通過監控這些數據狀態的變化,從而可以達到基於數據的集群管理。

數據模型

與Linux文件系統不同的是,Linux文件系統有目錄和文件的區別,而Zookeeper的數據節點稱為ZNode,ZNode是Zookeeper中數據的最小單元,每個ZNode都可以保存數據,同時還可以掛載子節點,因此構成了一個層次化的命名空間,稱為樹。

技術分享

Zookeeper中ZNode的節點創建時候是可以指定類型的,主要有下面幾種類型。

  • PERSISTENT:持久化ZNode節點,一旦創建這個ZNode點存儲的數據不會主動消失,除非是客戶端主動的delete。

  • EPHEMERAL:臨時ZNode節點,Client連接到Zookeeper Service的時候會建立一個Session,之後用這個Zookeeper連接實例創建該類型的znode,一旦Client關閉了Zookeeper的連接,服務器就會清除Session,然後這個Session建立的ZNode節點都會從命名空間消失。總結就是,這個類型的znode的生命周期是和Client建立的連接一樣的。

  • PERSISTENT_SEQUENTIAL:順序自動編號的ZNode節點,這種znoe節點會根據當前已近存在的ZNode節點編號自動加 1,而且不會隨Session斷開而消失。

  • EPEMERAL_SEQUENTIAL:臨時自動編號節點,ZNode節點編號會自動增加,但是會隨Session消失而消失

Watcher數據變更通知

Zookeeper使用Watcher機制實現分布式數據的發布/訂閱功能。

技術分享

Zookeeper的Watcher機制主要包括客戶端線程、客戶端WatcherManager、Zookeeper服務器三部分。客戶端在向Zookeeper服務器註冊的同時,會將Watcher對象存儲在客戶端的WatcherManager當中。當Zookeeper服務器觸發Watcher事件後,會向客戶端發送通知,客戶端線程從WatcherManager中取出對應的Watcher對象來執行回調邏輯。

ACL保障數據的安全

Zookeeper內部存儲了分布式系統運行時狀態的元數據,這些元數據會直接影響基於Zookeeper進行構造的分布式系統的運行狀態,如何保障系統中數據的安全,從而避免因誤操作而帶來的數據隨意變更而導致的數據庫異常十分重要,Zookeeper提供了一套完善的ACL權限控制機制來保障數據的安全。

我們可以從三個方面來理解ACL機制:權限模式 Scheme、授權對象 ID、權限 Permission,通常使用"scheme:id:permission"來標識一個有效的ACL信息。

內存數據

Zookeeper的數據模型是樹結構,在內存數據庫中,存儲了整棵樹的內容,包括所有的節點路徑、節點數據、ACL信息,Zookeeper會定時將這個數據存儲到磁盤上。

  • DataTree:DataTree是內存數據存儲的核心,是一個樹結構,代表了內存中一份完整的數據。DataTree不包含任何與網絡、客戶端連接及請求處理相關的業務邏輯,是一個獨立的組件。

  • DataNode:DataNode是數據存儲的最小單元,其內部除了保存了結點的數據內容、ACL列表、節點狀態之外,還記錄了父節點的引用和子節點列表兩個屬性,其也提供了對子節點列表進行操作的接口。

  • ZKDatabase:Zookeeper的內存數據庫,管理Zookeeper的所有會話、DataTree存儲和事務日誌。ZKDatabase會定時向磁盤dump快照數據,同時在Zookeeper啟動時,會通過磁盤的事務日誌和快照文件恢復成一個完整的內存數據庫。

Zookeeper的實現原理分析

1. Zookeeper Service網絡結構

Zookeeper的工作集群可以簡單分成兩類,一個是Leader,唯一一個,其余的都是follower,如何確定Leader是通過內部選舉確定的。

技術分享

  • Leader和各個follower是互相通信的,對於Zookeeper系統的數據都是保存在內存裏面的,同樣也會備份一份在磁盤上。

  • 如果Leader掛了,Zookeeper集群會重新選舉,在毫秒級別就會重新選舉出一個Leader。

  • 集群中除非有一半以上的Zookeeper節點掛了,Zookeeper Service才不可用。

2. Zookeeper讀寫數據

技術分享

  • 寫數據,一個客戶端進行寫數據請求時,如果是follower接收到寫請求,就會把請求轉發給Leader,Leader通過內部的Zab協議進行原子廣播,直到所有Zookeeper節點都成功寫了數據後(內存同步以及磁盤更新),這次寫請求算是完成,然後Zookeeper Service就會給Client發回響應。

  • 讀數據,因為集群中所有的Zookeeper節點都呈現一個同樣的命名空間視圖(就是結構數據),上面的寫請求已經保證了寫一次數據必須保證集群所有的Zookeeper節點都是同步命名空間的,所以讀的時候可以在任意一臺Zookeeper節點上。

3. Zookeeper工作原理

Zab協議

Zookeeper的核心是廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。

Zab(ZooKeeper Atomic Broadcast)原子消息廣播協議作為數據一致性的核心算法,Zab協議是專為Zookeeper設計的支持崩潰恢復原子消息廣播算法。

Zab協議核心如下:

所有的事務請求必須一個全局唯一的服務器(Leader)來協調處理,集群其余的服務器稱為follower服務器。Leader服務器負責將一個客戶端請求轉化為事務提議(Proposal),並將該proposal分發給集群所有的follower服務器。之後Leader服務器需要等待所有的follower服務器的反饋,一旦超過了半數的follower服務器進行了正確反饋後,那麽Leader服務器就會再次向所有的follower服務器分發commit消息,要求其將前一個proposal進行提交。

Zab模式

Zab協議包括兩種基本的模式:崩潰恢復消息廣播

  • 當整個服務框架啟動過程中或Leader服務器出現網絡中斷、崩潰退出與重啟等異常情況時,Zab協議就會進入恢復模式並選舉產生新的Leader服務器。

  • 當選舉產生了新的Leader服務器,同時集群中已經有過半的機器與該Leader服務器完成了狀態同步之後,Zab協議就會退出恢復模式,狀態同步是指數據同步,用來保證集群在過半的機器能夠和Leader服務器的數據狀態保持一致。

  • 當集群中已經有過半的Follower服務器完成了和Leader服務器的狀態同步,那麽整個服務框架就可以進入消息廣播模式。

  • 當一臺同樣遵守Zab協議的服務器啟動後加入到集群中,如果此時集群中已經存在一個Leader服務器在負責進行消息廣播,那麽加入的服務器就會自覺地進入數據恢復模式:找到Leader所在的服務器,並與其進行數據同步,然後一起參與到消息廣播流程中去。

Zookeeper只允許唯一的一個Leader服務器來進行事務請求的處理,Leader服務器在接收到客戶端的事務請求後,會生成對應的事務提議並發起一輪廣播協議,而如果集群中的其他機器收到客戶端的事務請求後,那麽這些非Leader服務器會首先將這個事務請求轉發給Leader服務器。

消息廣播

技術分享

Zab協議的消息廣播過程使用是一個原子廣播協議,類似一個2PC提交過程。具體的:

  • ZooKeeper使用單一主進程Leader用於處理客戶端所有事務請求,並采用Zab的原子廣播協議,將服務器數據狀態變更以事務Proposal的形式廣播Follower上,因此能很好的處理客戶端的大量並發請求。

  • 另一方面,由於事務間可能存在著依賴關系,Zab協議保證Leader廣播的變更序列被順序的處理,有些狀態的變更必須依賴於比它早生成的那些狀態變更。

  • 最後,考慮到主進程Leader在任何時候可能崩潰或者異常退出, 因此Zab協議還要Leader進程崩潰的時候可以重新選出Leader並且保證數據的完整性;Follower收到Proposal後,寫到磁盤,返回Ack。Leader收到大多數ACK後,廣播Commit消息,自己也提交該消息。Follower收到Commit之後,提交該消息。

Zab協議簡化了2PC事務提交:

  • 去除中斷邏輯移除,follower要麽ack,要麽拋棄Leader。

  • Leader不需要所有的Follower都響應成功,只要一個多數派Ack即可。

崩潰恢復

上面我們講了Zab協議在正常情況下的消息廣播過程,那麽一旦Leader服務器出現崩潰或者與過半的follower服務器失去聯系,就進入崩潰恢復模式。

恢復模式需要重新選舉出一個新的Leader,讓所有的Server都恢復到一個正確的狀態。

Zookeeper實踐,共享鎖,Leader選舉

分布式鎖用於控制分布式系統之間同步訪問共享資源的一種方式,可以保證不同系統訪問一個或一組資源時的一致性,主要分為排它鎖和共享鎖。

  • 排它鎖又稱為寫鎖或獨占鎖,若事務T1對數據對象O1加上了排它鎖,那麽在整個加鎖期間,只允許事務T1對O1進行讀取和更新操作,其他任何事務都不能再對這個數據對象進行任何類型的操作,直到T1釋放了排它鎖。

技術分享

  • 共享鎖又稱為讀鎖,若事務T1對數據對象O1加上共享鎖,那麽當前事務只能對O1進行讀取操作,其他事務也只能對這個數據對象加共享鎖,直到該數據對象上的所有共享鎖都被釋放。

技術分享

推薦文章:基於Zk實現分布式鎖

Leader選舉

Leader選舉是保證分布式數據一致性的關鍵所在。當Zookeeper集群中的一臺服務器出現以下兩種情況之一時,需要進入Leader選舉。

  • 服務器初始化啟動。

  • 服務器運行期間無法和Leader保持連接。

Zookeeper在3.4.0版本後只保留了TCP版本的 FastLeaderElection 選舉算法。當一臺機器進入Leader選舉時,當前集群可能會處於以下兩種狀態:

  • 集群中已存在Leader。

  • 集群中不存在Leader。

對於集群中已經存在Leader而言,此種情況一般都是某臺機器啟動得較晚,在其啟動之前,集群已經在正常工作,對這種情況,該機器試圖去選舉Leader時,會被告知當前服務器的Leader信息,對於該機器而言,僅僅需要和Leader機器建立起連接,並進行狀態同步即可。

而在集群中不存在Leader情況下則會相對復雜,其步驟如下:

(1) 第一次投票。無論哪種導致進行Leader選舉,集群的所有機器都處於試圖選舉出一個Leader的狀態,即LOOKING狀態,LOOKING機器會向所有其他機器發送消息,該消息稱為投票。投票中包含了SID(服務器的唯一標識)和ZXID(事務ID),(SID, ZXID)形式來標識一次投票信息。假定Zookeeper由5臺機器組成,SID分別為1、2、3、4、5,ZXID分別為9、9、9、8、8,並且此時SID為2的機器是Leader機器,某一時刻,1、2所在機器出現故障,因此集群開始進行Leader選舉。在第一次投票時,每臺機器都會將自己作為投票對象,於是SID為3、4、5的機器投票情況分別為(3, 9),(4, 8), (5, 8)。

(2) 變更投票。每臺機器發出投票後,也會收到其他機器的投票,每臺機器會根據一定規則來處理收到的其他機器的投票,並以此來決定是否需要變更自己的投票,這個規則也是整個Leader選舉算法的核心所在,其中術語描述如下

  • vote_sid:接收到的投票中所推舉Leader服務器的SID。

  • vote_zxid:接收到的投票中所推舉Leader服務器的ZXID。

  • self_sid:當前服務器自己的SID。

  • self_zxid:當前服務器自己的ZXID。

每次對收到的投票的處理,都是對(vote_sid, vote_zxid)和(self_sid, self_zxid)對比的過程。

  • 規則一:如果vote_zxid大於self_zxid,就認可當前收到的投票,並再次將該投票發送出去。

  • 規則二:如果vote_zxid小於self_zxid,那麽堅持自己的投票,不做任何變更。

  • 規則三:如果vote_zxid等於self_zxid,那麽就對比兩者的SID,如果vote_sid大於self_sid,那麽就認可當前收到的投票,並再次將該投票發送出去。

  • 規則四:如果vote_zxid等於self_zxid,並且vote_sid小於self_sid,那麽堅持自己的投票,不做任何變更。

  • 結合上面規則,給出下面的集群變更過程。

技術分享

(3) 確定Leader。經過第二輪投票後,集群中的每臺機器都會再次接收到其他機器的投票,然後開始統計投票,如果一臺機器收到了超過半數的相同投票,那麽這個投票對應的SID機器即為Leader。此時Server3將成為Leader。

由上面規則可知,通常那臺服務器上的數據越新(ZXID會越大),其成為Leader的可能性越大,也就越能夠保證數據的恢復。如果ZXID相同,則SID越大機會越大。

「 淺談大規模分布式系統中那些技術點」系列文章:

  • 淺談分布式事務

Reference

http://www.cnblogs.com/yuyijq/p/3391945.html

http://www.cnblogs.com/kms1989/p/5504505.html

http://www.hollischuang.com/archives/1275

http://www.jianshu.com/p/bf32e44d3113

http://www.jianshu.com/p/4654bdbb8792

http://www.jianshu.com/p/8fba732af0cd

http://www.jianshu.com/p/6af7362701c5

http://www.jianshu.com/p/6929446d3b10

http://www.jianshu.com/p/5dce97c9ba85

http://www.cnblogs.com/sunddenly/articles/4073157.html

http://www.dczou.com/viemall/454.html


轉載請並標註: “本文轉載自 linkedkeeper.com (文/張松然)”

【轉】淺談分布式服務協調技術 Zookeeper