我們一塊兒聊聊Zookeeper

Google的三篇論文影響了不少不少人,也影響了不少不少系統。這三篇論文一直是分佈式領域傳閱的經典。根據MapReduce,因而咱們有了Hadoop;根據GFS,因而咱們有了HDFS;根據BigTable,因而咱們有了HBase。而在這三篇論文裏都說起Google的一個Lock Service —— Chubby,哦,因而咱們有了Zookeeper。node

隨着大數據的火熱,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的關係

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

CAP關係

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

ZooKeeper是分佈式協調服務,它的職責是保證數據在其管轄下的全部服務之間保持同步、一致;因此就不難理解爲何ZooKeeper被設計成CP而不是AP特性的了。並且, 做爲ZooKeeper的核心實現算法Zab,就是解決了分佈式系統下數據如何在多個服務之間保持同步問題的。併發

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

Zookeeper提供基於相似於文件系統的目錄節點樹方式的數據存儲,可是Zookeeper並非用來專門存儲數據的,它的做用主要是用來維護和監控你存儲的數據的狀態變化。經過監控這些數據狀態的變化,從而能夠達到基於數據的集羣管理。框架

數據模型

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

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機制實現分佈式數據的發佈/訂閱功能。

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是經過內部選舉肯定的。

Zookeeper架構圖

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

若是Leader掛了,Zookeeper集羣會從新選舉,在毫秒級別就會從新選舉出一個Leader。

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

2. Zookeeper讀寫數據

zk讀取數據流程

寫數據,一個客戶端進行寫數據請求時,若是是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進行讀取操做,其餘事務也只能對這個數據對象加共享鎖,直到該數據對象上的全部共享鎖都被釋放。

共享鎖

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分別爲一、二、三、四、5,ZXID分別爲九、九、九、八、8,而且此時SID爲2的機器是Leader機器,某一時刻,一、2所在機器出現故障,所以集羣開始進行Leader選舉。在第一次投票時,每臺機器都會將本身做爲投票對象,因而SID爲三、四、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,那麼堅持本身的投票,不作任何變動。

結合上面規則,給出下面的集羣變動過程。

Leader選舉

(3) 肯定Leader。通過第二輪投票後,集羣中的每臺機器都會再次接收到其餘機器的投票,而後開始統計投票,若是一臺機器收到了超過半數的相同投票,那麼這個投票對應的SID機器即爲Leader。此時Server3將成爲Leader。

由上面規則可知,一般那臺服務器上的數據越新(ZXID會越大),其成爲Leader的可能性越大,也就越可以保證數據的恢復。若是ZXID相同,則SID越大機會越大。

相關文章
相關標籤/搜索