本文將講解Zookeeper的原理特性以及典型使用案例,部分資源來自網路
1.ZooKeeper 原理
Apache ZooKeeper是努力發展和維持一個開源的服務器,這使得高度可靠的分布式協調。ZooKeeper是用於維持配置信息,命名,提供分布式同步,並提供分組服務的集中式服務。
ZooKeeper允許分布式進程相互協調,通過共享式的名字空間數據寄存器(我們稱這些寄存器znodes),就像文件系統。不同於普通的文件系zookeeper提供其客戶提供高吞吐量、低延遲、高可用、嚴格有序的進入znodes。在性能方面的優勢讓它被用在大型的分布式系統。可靠性方面,防止它成為大系統的單點故障。其嚴格的命令允許復雜的同步原語是在客戶端實現。
ZooKeeper提供的名稱空間更像是一個標准的文件系統。一個名字是一個序列的路徑元素由斜杠分隔(“/”)。在ZooKeeper的名稱空間,每個znode的路徑標識。每個znode有父的路徑是前綴少一層的znode;此規則的例外是根(“/”)沒有父。而且,就像標准的文件系統,一個存在子節點的節點是不能被刪除的。
ZooKeeper和標准文件系統的主要區別是,每個znode可以有與它相關的數據(每個文件也可以是目錄,反之亦然),znodes限於它們可以具有的數據量。ZooKeeper被設計用來存儲坐標數據:狀態信息、配置、位置信息等這樣的元信息通常以千字節為單位。ZooKeeper有1M的一個內置的完整性檢查,以防止它被用作一個大的數據存儲,但一般它是用來存儲小得多的數據塊。
該服務本身是復制了一組包括服務的機器。這些機器保持在數據樹的存儲的鏡像以及在持久性存儲事務日志和快照。因為數據被保持在內存儲,ZooKeeper能夠獲得很高的吞吐量和低延遲的數據。缺點到內存數據庫是該Zookeeper可以管理數據庫的大小是由內存的限制。這也是znodes只能存儲小的數據量原因。
組成的ZooKeeper服務的服務器都必須互相了解。只要大多數的服務器可用,ZooKeeper的服務將是可用的。用戶還必須知道服務器的列表。客戶端創建一個句柄使用的服務器此列表中的ZooKeeper服務。
客戶端只能連接到一個單一的ZooKeeper服務器。客戶機維護通過它發送請求時,獲取響應,獲取觀看事件,並發送心跳TCP連接。如果TCP連接到服務器斷開,客戶端將連接到不同的服務器。當客戶端第一次連接到的ZooKeeper服務第一的ZooKeeper服務器將安裝客戶端的會話。如果客戶端需要連接到另一台服務器,將會與新得服務器重建會話。
閱讀由ZooKeeper客戶端發送請求在該客戶端所連接的服務器的ZooKeeper本地處理。如果該讀請求在znode注冊的,該watch事件還跟蹤在ZooKeeper服務器。寫請求轉發到其他的ZooKeeper服務器,並通過共識產生一個響應之前。同步請求也被轉送到另一台服務器,但實際上並沒有達成一致。因此,隨着服務器數量的讀請求的吞吐量和寫請求的吞吐量隨服務器的數量而減少。
順序在ZooKeeper中是非常重要的; 所有的更新都完全是排序的。ZooKeeper的實際標識反映這個順序每次更新。我們稱這個號zxid(ZooKeeper的事務ID)。每次更新都會有一個獨特的zxid。讀取(和Watchs)相對於更新順序。讀取響應將加蓋上zxid由服務器讀取處理服務。
- Znode
ZooKeeper目錄樹中每一個節點對應一個Znode。每個Znode維護着一個屬性結構,它包含着版本號(dataVersion),時間戳(ctime,mtime)等狀態信息,ZooKeeper正是使用節點的這些特性來實現它的某些特定功能。每當Znode的數據改變時,他相應的版本號將會增加。每當客戶端檢索數據時,它將同時檢索數據的版本號。並且如果一個客戶端執行了某個節點的更新或刪除操作,他也必須提供要被操作的數據版本號。如果所提供的數據版本號與實際不匹配,那么這個操作將會失敗。
Znode是客戶端訪問ZooKeeper的主要實體,它包含以下幾個特征:
(1)Watches
客戶端可以在節點上設置watch(我們稱之為監視器)。當節點狀態發生改變時(數據的增、刪、改)將會觸發watch所對應的操作。當watch被觸發時,ZooKeeper將會向客戶端發送且僅發送一條通知,因為watch只能被觸發一次。
(2)數據訪問
ZooKeeper中的每個節點存儲的數據要被原子性的操作。也就是說讀操作將獲取與節點相關的所有數據,寫操作也將替換掉節點的所有數據。另外,每一個節點都擁有自己的ACL(訪問控制列表),這個列表規定了用戶的權限,即限定了特定用戶對目標節點可以執行的操作。
(3)節點類型
ZooKeeper中的節點有兩種,分別為臨時節點和永久節點。節點的類型在創建時即被確定,並且不能改變。
ZooKeeper的臨時節點:該節點的生命周期依賴於創建它們的會話。一旦會話結束,臨時節點將被自動刪除,當然可以也可以手動刪除。另外,需要注意是, ZooKeeper的臨時節點不允許擁有子節點。
ZooKeeper的永久節點:該節點的生命周期不依賴於會話,並且只有在客戶端顯示執行刪除操作的時候,他們才能被刪除。
(4)順序節點(唯一性的保證)
當創建Znode的時候,用戶可以請求在ZooKeeper的路徑結尾添加一個遞增的計數。這個計數對於此節點的父節點來說是唯一的,它的格式為"%10d"(10位數字,沒有數值的數位用0補充,例如"0000000001")。當計數值大於232-1時,計數器將溢出。
創建的Znode有以下幾種類型:
PERSISTENT:永久節點
EPHEMERAL:臨時節點
PERSISTENT_SEQUENTIAL:永久節點、序列化
EPHEMERAL_SEQUENTIAL:臨時節點、序列化
3.Zookeeper的特點
-
最終一致性:client不論連接到哪個Server,展示給它都是同一個視圖,這是zookeeper最重要的性能。
-
可靠性:具有簡單、健壯、良好的性能,如果消息m被一台服務器接受,那么它將被所有的服務器接受。
-
實時性:Zookeeper保證客戶端將在一個時間間隔范圍內獲得服務器的更新信息,或者服務器失效的信息。 但由於網絡延時等原因,Zookeeper不能保證兩個客戶端能同時得到剛更新的數據,如果需要最新數據,應該在讀數據之前調用sync()接口。
-
等待無關(wait-free):慢的或者失效的client,不得干預快速的client的請求,使得每個client都能有效的等待。
-
原子性:更新只能成功或者失敗,沒有中間狀態。
-
順序性:包括全局有序和偏序兩種:
-
全局有序:是指如果在一台服務器上消息a在消息b前發布,則在所有Server上消息a都將在消息b前被發布;
-
偏序:是指如果一個消息b在消息a后被同一個發送者發布,a必將排在b前面
4.應用場景
場景類別 | 典型場景描述(ZK特性,使用方法) | 應用中的具體使用 |
數據發布與訂閱 | 發布與訂閱即所謂的配置管理,顧名思義就是將數據發布到zk節點上,供訂閱者動態獲取數據,實現配置信息的集中式管理和動態更新。例如全局的配置信息,地址列表等就非常適合使用。 | 1. 索引信息和集群中機器節點狀態存放在zk的一些指定節點,供各個客戶端訂閱使用。 2. 系統日志(經過處理后的)存儲,這些日志通常2-3天后被清除。 3. 應用中用到的一些配置信息集中管理,在應用啟動的時候主動來獲取一次,並且在節點上注冊一個Watcher,以后每次配置有更新,實時通知到應用,獲取最新配置信息。 4. 業務邏輯中需要用到的一些全局變量,比如一些消息中間件的消息隊列通常有個offset,這個offset存放在zk上,這樣集群中每個發送者都能知道當前的發送進度。 5. 系統中有些信息需要動態獲取,並且還會存在人工手動去修改這個信息。以前通常是暴露出接口,例如JMX接口,有了zk后,只要將這些信息存放到zk節點上即可。 |
Name Service | 這個主要是作為分布式命名服務,通過調用zk的create node api,能夠很容易創建一個全局唯一的path,這個path就可以作為一個名稱。 | |
分布通知/協調 | ZooKeeper中特有watcher注冊與異步通知機制,能夠很好的實現分布式環境下不同系統之間的通知與協調,實現對數據變更的實時處理。使用方法通常是不同系統都對ZK上同一個znode進行注冊,監聽znode的變化(包括znode本身內容及子節點的),其中一個系統update了znode,那么另一個系統能夠收到通知,並作出相應處理。 | 1. 另一種心跳檢測機制:檢測系統和被檢測系統之間並不直接關聯起來,而是通過zk上某個節點關聯,大大減少系統耦合。 2. 另一種系統調度模式:某系統有控制台和推送系統兩部分組成,控制台的職責是控制推送系統進行相應的推送工作。管理人員在控制台作的一些操作,實際上是修改了ZK上某些節點的狀態,而zk就把這些變化通知給他們注冊Watcher的客戶端,即推送系統,於是,作出相應的推送任務。
3. 另一種工作匯報模式:一些類似於任務分發系統,子任務啟動后,到zk來注冊一個臨時節點,並且定時將自己的進度進行匯報(將進度寫回這個臨時節點),這樣任務管理者就能夠實時知道任務進度。 總之,使用zookeeper來進行分布式通知和協調能夠大大降低系統之間的耦合。 |
分布式鎖 | 分布式鎖,這個主要得益於ZooKeeper為我們保證了數據的強一致性,即用戶只要完全相信每時每刻,zk集群中任意節點(一個zk server)上的相同znode的數據是一定是相同的。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序。
所謂保持獨占,就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過create znode的方式來實現。所有客戶端都去創建 /distribute_lock 節點,最終成功創建的那個客戶端也即擁有了這把鎖。 控制時序,就是所有視圖來獲取這個鎖的客戶端,最終都是會被安排執行,只是有個全局時序了。做法和上面基本類似,只是這里 /distribute_lock 已經預先存在,客戶端在它下面創建臨時有序節點(這個可以通過節點的屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。Zk的父節點(/distribute_lock)維持一份sequence,保證子節點創建的時序性,從而也形成了每個客戶端的全局時序。 |
|
集群管理 | 1. 集群機器監控:這通常用於那種對集群中機器狀態,機器在線率有較高要求的場景,能夠快速對集群中機器變化作出響應。這樣的場景中,往往有一個監控系統,實時檢測集群機器是否存活。過去的做法通常是:監控系統通過某種手段(比如ping)定時檢測每個機器,或者每個機器自己定時向監控系統匯報“我還活着”。 這種做法可行,但是存在兩個比較明顯的問題:1. 集群中機器有變動的時候,牽連修改的東西比較多。2. 有一定的延時。
利用ZooKeeper有兩個特性,就可以實時另一種集群機器存活性監控系統: a. 客戶端在節點 x 上注冊一個Watcher,那么如果 x 的子節點變化了,會通知該客戶端。 b. 創建EPHEMERAL類型的節點,一旦客戶端和服務器的會話結束或過期,那么該節點就會消失。 例如,監控系統在 /clusterServers 節點上注冊一個Watcher,以后每動態加機器,那么就往 /clusterServers 下創建一個 EPHEMERAL類型的節點:/clusterServers/{hostname}. 這樣,監控系統就能夠實時知道機器的增減情況,至於后續處理就是監控系統的業務了。 在分布式環境中,相同的業務應用分布在不同的機器上,有些業務邏輯(例如一些耗時的計算,網絡I/O處理),往往只需要讓整個集群中的某一台機器進行執行,其余機器可以共享這個結果,這樣可以大大減少重復勞動,提高性能,於是這個master選舉便是這種場景下的碰到的主要問題。 利用ZooKeeper的強一致性,能夠保證在分布式高並發情況下節點創建的全局唯一性,即:同時有多個客戶端請求創建 /currentMaster 節點,最終一定只有一個客戶端請求能夠創建成功。 利用這個特性,就能很輕易的在分布式環境中進行集群選取了。 另外,這種場景演化一下,就是動態Master選舉。這就要用到 EPHEMERAL_SEQUENTIAL類型節點的特性了。 上文中提到,所有客戶端創建請求,最終只有一個能夠創建成功。在這里稍微變化下,就是允許所有請求都能夠創建成功,但是得有個創建順序,於是所有的請求最終在ZK上創建結果的一種可能情況是這樣: /currentMaster/{sessionId}-1 , /currentMaster/{sessionId}-2 , /currentMaster/{sessionId}-3 ….. 每次選取序列號最小的那個機器作為Master,如果這個機器掛了,由於他創建的節點會馬上小時,那么之后最小的那個機器就是Master了。 |
1. 在搜索系統中,如果集群中每個機器都生成一份全量索引,不僅耗時,而且不能保證彼此之間索引數據一致。因此讓集群中的Master來進行全量索引的生成,然后同步到集群中其它機器。 2. 另外,Master選舉的容災措施是,可以隨時進行手動指定master,就是說應用在zk在無法獲取master信息時,可以通過比如http方式,向一個地方獲取master。 |
分布式隊列 | 隊列方面,我目前感覺有兩種,一種是常規的先進先出隊列,另一種是要等到隊列成員聚齊之后的才統一按序執行。對於第二種先進先出隊列,和分布式鎖服務中的控制時序場景基本原理一致,這里不再贅述。
第二種隊列其實是在FIFO隊列的基礎上作了一個增強。通常可以在 /queue 這個znode下預先建立一個/queue/num 節點,並且賦值為n(或者直接給/queue賦值n),表示隊列大小,之后每次有隊列成員加入后,就判斷下是否已經到達隊列大小,決定是否可以開始執行了。這種用法的典型場景是,分布式環境中,一個大任務Task A,需要在很多子任務完成(或條件就緒)情況下才能進行。這個時候,凡是其中一個子任務完成(就緒),那么就去 /taskList 下建立自己的臨時時序節點(CreateMode.EPHEMERAL_SEQUENTIAL),當 /taskList 發現自己下面的子節點滿足指定個數,就可以進行下一步按序進行處理了。 |
感謝:
本文引用以下朋友博客,排名不分先后,若有問題,請聯系刪除
小武哥 : http://www.wuzesheng.com/?p=2609
吳超沉思錄:http://www.superwu.cn/