一文了解Zookeeper

前言

一直想找時間 好好寫一篇關於Zookeeper的博客,雨後的湖大 消除熱夏的酷暑,空氣變得清新,安靜下來可以聽到窗外的蛙聲。於是乎 整理自己的一些筆記,寫下一篇關於Zookeeper的博文。話不多說,乾貨送上~

Zookeeper概覽

Zookeeper,中文名是動物園管理員。它是一個開源的分佈式協調服務,ZooKeeper 框架最初是在“Yahoo!"上構建的,用於以簡單而穩健的方式訪問他們的應用程序。
後來,Apache ZooKeeper 成爲 Hadoop,HBase 和其他分佈式框架使用的有組織服務的標準。例如,Apache HBase 使用 ZooKeeper 跟蹤分佈式數據的狀態。

ZooKeeper 的設計目標是將那些複雜且容易出錯的分佈式一致性服務封裝起來,構成一個高效可靠的原語集,並以一系列簡單易用的接口提供給用戶使用

原語: 操作系統或計算機網絡用語範疇。它是由若干條指令組成的,用於完成一定功能的一個過程。具有不可分割性,即原語的執行必須是連續的,在執行過程中不允許被中斷。

ZooKeeper 是一個典型的分佈式數據一致性解決方案,他實現的功能有:
1.命名服務 2.配置管理 3.集羣管理 4.分佈式鎖 5.隊列管理
(後續會對這幾個方面做詳細展開~)

Zookeeper基本概念

1. Zookeeper的角色

首先講解一下Zookeeper集羣中每個server所承擔的角色,它們是以下三種中的一種:
(1)leader
一個Zookeeper集羣同一時間只會有一個實際工作的Leader,它會發起並維護與各Follwer及Observer間的心跳。

(2)follower

  • 一個Zookeeper集羣可能同時存在多個Follower,它會響應Leader的心跳,
  • Follower可直接處理並返回客戶端的讀請求,同時會將寫請求轉發給Leader處理,
  • 並且負責在Leader處理寫請求時對請求進行投票。

(3)observer
角色與Follower類似,但是無投票權。爲了支持更多的客戶端,需要增加更多Server;Server增多,投票階段延遲增大,影響性能;引入Observer,Observer不參與投票; Observers接受客戶端的連接,並將寫請求轉發給leader節點; 加入更多Observer節點,提高伸縮性,同時不影響吞吐率。

工作流程如下圖所示:
在這裏插入圖片描述
總結概括三者的關係,如下圖所示:
在這裏插入圖片描述

2. 會話(Session)

Session 指的是 ZooKeeper 服務器與客戶端會話。在 ZooKeeper 中,一個客戶端連接是指客戶端和服務器之間的一個 TCP 長連接

客戶端啓動的時候,首先會與服務器建立一個 TCP 連接,從第一次連接建立開始,客戶端會話的生命週期也開始了。

通過這個連接,客戶端能夠通過心跳檢測與服務器保持有效的會話,也能夠向 Zookeeper 服務器發送請求並接受響應,同時還能夠通過該連接接收來自服務器的 Watch 事件通知。

Session 的 sessionTimeout 值用來設置一個客戶端會話的超時時間。

當由於服務器壓力太大、網絡故障或是客戶端主動斷開連接等各種原因導致客戶端連接斷開時,只要在 sessionTimeout 規定的時間內能夠重新連接上集羣中任意一臺服務器,那麼之前創建的會話仍然有效。

在爲客戶端創建會話之前,服務端首先會爲每個客戶端都分配一個 sessionID。

由於 sessionID 是 Zookeeper 會話的一個重要標識,許多與會話相關的運行機制都是基於這個 sessionID 的。

因此,無論是哪臺服務器爲客戶端分配的 sessionID,都務必保證全局唯一。

3. Znode

在談到分佈式的時候,我們通常說的“節點"是指組成集羣的每一臺機器。
然而,在 ZooKeeper 中,“節點"分爲兩類:

  • 第一類同樣是指構成集羣的機器,我們稱之爲機器節點。
  • 第二類則是指數據模型中的數據單元,我們稱之爲數據節點一ZNode

ZooKeeper 將所有數據存儲在內存中,數據模型是一棵樹(Znode Tree),由斜槓(/)的進行分割的路徑,就是一個 Znode,例如/foo/path1。每個上都會保存自己的數據內容,同時還會保存一系列屬性信息。

每個子目錄項如 NameService 都被稱作爲znode,和文件系統一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在於**znode是可以存儲數據的**

有四種類型的znode:
1、PERSISTENT-持久化目錄節點
客戶端與zookeeper斷開連接後,該節點依舊存在

2、PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點
客戶端與zookeeper斷開連接後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號

3、EPHEMERAL-臨時目錄節點
客戶端與zookeeper斷開連接後,該節點被刪除

4、EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點
客戶端與zookeeper斷開連接後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號
在這裏插入圖片描述

4. 版本

在前面我們已經提到,Zookeeper 的每個 ZNode 上都會存儲數據,對應於每個 ZNode,Zookeeper 都會爲其維護一個叫作 Stat 的數據結構。

Stat 中記錄了這個 ZNode 的三個數據版本,分別是:

  • version(當前 ZNode 的版本)
  • cversion(當前 ZNode 子節點的版本)
  • aversion(當前 ZNode 的 ACL 版本)

5. Watcher

Watcher(事件監聽器),是 ZooKeeper 中的一個很重要的特性。
ZooKeeper 允許用戶在指定節點上註冊一些 Watcher,並且在一些特定事件觸發的時候,ZooKeeper 服務端會將事件通知到感興趣的客戶端上去,該機制是 ZooKeeper 實現分佈式協調服務的重要特性。

最後總結一下zookeeper中一些重要概念:

  • ZooKeeper 本身就是一個分佈式程序(只要半數以上節點存活,ZooKeeper 就能正常服務)。
  • 爲了保證高可用,最好是以集羣形態來部署 ZooKeeper,這樣只要集羣中大部分機器是可用的(能夠容忍一定的機器故障),那麼 ZooKeeper 本身仍然是可用的。
  • ZooKeeper 將數據保存在內存中,這也就保證了 高吞吐量和低延遲(但是內存限制了能夠存儲的容量不太大,此限制也是保持 Znode 中存儲的數據量較小的進一步原因)。
  • ZooKeeper 是高性能的。在“讀”多於“寫”的應用程序中尤其地高性能,因爲“寫”會導致所有的服務器間同步狀態。(“讀”多於“寫”是協調服務的典型場景。)
  • ZooKeeper 有臨時節點的概念。當創建臨時節點的客戶端會話一直保持活動,瞬時節點就一直存在。而當會話終結時,瞬時節點被刪除。持久節點是指一旦這個 ZNode 被創建了,除非主動進行 ZNode 的移除操作,否則這個 ZNode 將一直保存在 Zookeeper 上。
  • ZooKeeper 底層其實只提供了兩個功能:①管理(存儲、讀取)用戶程序提交的數據;②爲用戶程序提交數據節點監聽服務。

ZAB 協議 & Paxos 算法

Paxos 算法可以說是 ZooKeeper 的靈魂了。但是,ZooKeeper 並沒有完全採用 Paxos 算法 ,而是使用 ZAB 協議作爲其保證數據一致性的核心算法。

另外,在 ZooKeeper 的官方文檔中也指出,ZAB 協議並不像 Paxos 算法那樣,是一種通用的分佈式一致性算法,它是一種特別爲 ZooKeeper 設計的崩潰可恢復的原子消息廣播算法。

ZAB 協議介紹

Zookeeper 的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議
ZAB(ZooKeeper Atomic Broadcast 原子廣播)協議是爲分佈式協調服務 ZooKeeper 專門設計的一種支持崩潰恢復的原子廣播協議。

在 ZooKeeper 中,主要依賴 ZAB 協議來實現分佈式數據一致性,基於該協議,ZooKeeper 實現了一種主備模式的系統架構來保持集羣中各個副本之間的數據一致性。

事務編號 Zxid(事務請求計數器+ epoch)
在 ZAB ( ZooKeeper Atomic Broadcast , ZooKeeper 原子消息廣播協議) 協議的事務編號 Zxid 設計中,Zxid 是一個 64 位的數字,其中低 32 位是一個簡單的單調遞增的計數器,針對客戶端每一個事務請求,計數器加 1;而高 32 位則代表 Leader 週期 epoch 的編號,每個當選產生一個新的 Leader 服務器,就會從這個 Leader 服務器上取出其本地日誌中最大事務的ZXID,並從中讀取 epoch 值,然後加 1,以此作爲新的 epoch,並將低 32 位從 0 開始計數。

Zxid(Transaction id)類似於RDBMS中的事務ID,用於標識一次更新操作的Proposal(提議) ID。爲了保證順序性,該zkid必須單調遞增。

epoch:可以理解爲當前集羣所處的年代或者週期,每個 leader 就像皇帝,都有自己的年號,所以每次改朝換代,leader 變更之後,都會在前一個年代的基礎上加 1。這樣就算舊的 leader 崩潰恢復之後,也沒有人聽他的了,因爲 follower 只聽從當前年代的 leader 的命令。

ZAB 協議包括兩種基本的模式,分別是崩潰恢復和消息廣播

  • 當整個服務框架在啓動過程中,或是當 Leader 服務器出現網絡中斷、崩潰退出與重啓等異常情況時,ZAB 協議就會進入恢復模式並選舉產生新的 Leader 服務器。
  • 當選舉產生了新的 Leader 服務器,同時集羣中已經有過半的機器與該 Leader 服務器完成了狀態同步之後,ZAB 協議就會退出恢復模式。
    其中,所謂的狀態同步是指數據同步,用來保證集羣中存在過半的機器能夠和 Leader 服務器的數據狀態保持一致
  • 當集羣中已經有過半的 Follower 服務器完成了和 Leader 服務器的狀態同步,那麼整個服務框架就可以進人消息廣播模式了。
  • 當一臺同樣遵守 ZAB 協議的服務器啓動後加入到集羣中時,如果此時集羣中已經存在一個 Leader 服務器在負責進行消息廣播。
  • 那麼新加入的服務器就會自覺地進人數據恢復模式:找到 Leader 所在的服務器,並與其進行數據同步,然後一起參與到消息廣播流程中去。

正如上文介紹中所說的,ZooKeeper 設計成只允許唯一的一個 Leader 服務器來進行事務請求的處理。

Leader 服務器在接收到客戶端的事務請求後,會生成對應的事務提案併發起一輪廣播協議。

而如果集羣中的其他機器接收到客戶端的事務請求,那麼這些非 Leader 服務器會首先將這個事務請求轉發給 Leader 服務器。

Zookeeper 下 Server工作狀態

每個Server在工作過程中有三種狀態:

  • LOOKING:當前Server不知道leader是誰,正在搜尋
  • LEADING:當前Server即爲選舉出來的leader
  • FOLLOWING:leader已經選舉出來,當前Server與之同步

Zookeeper選主流程

當leader崩潰或者leader失去大多數的follower,這時候zk進入恢復模式,恢復模式需要重新選舉出一個新的leader,讓所有的Server都恢復到一個正確的狀態。

每個server首先給自己投票,然後用自己的選票和其他server選票對比,權重大的勝出,使用權重較大的更新自身選票箱。具體選舉過程如下:

  1. 每個Server啓動以後都詢問其它的Server它要投票給誰。對於其他server的詢問,server每次根據自己的狀態都回復自己推薦的leader的id和上一次處理事務的zxid(系統啓動時每個server都會推薦自己)
  2. 收到所有Server回覆以後,就計算出zxid最大的哪個Server,並將這個Server相關信息設置成下一次要投票的Server。
  3. 計算這過程中獲得票數最多的的sever爲獲勝者,如果獲勝者的票數超過半數,則改server被選爲leader。否則,繼續這個過程,直到leader被選舉出來
  4. leader就會開始等待server連接
  5. Follower連接leader,將最大的zxid發送給leader
  6. Leader根據follower的zxid確定同步點,至此選舉階段完成。
  7. 選舉階段完成Leader同步後通知follower 已經成爲uptodate狀態
  8. Follower收到uptodate消息後,又可以重新接受client的請求進行服務了

舉例,目前有5臺服務器,每臺服務器均沒有數據,它們的編號分別是1,2,3,4,5,按編號依次啓動,它們的選擇舉過程如下:

  1. 服務器1啓動,給自己投票,然後發投票信息,由於其它機器還沒有啓動所以它收不到反饋信息,服務器1的狀態一直屬於Looking。
  2. 服務器2啓動,給自己投票,同時與之前啓動的服務器1交換結果,由於服務器2的編號大所以服務器2勝出,但此時投票數沒有大於半數(服務器2的票數是2 大於半數至少是3),所以兩個服務器的狀態依然是LOOKING。
  3. 服務器3啓動,給自己投票,同時與之前啓動的服務器1,2交換信息,由於服務器3的編號最大所以服務器3勝出,此時投票數正好大於半數(服務器3的票數是3),所以服務器3成爲領導者,服務器1,2成爲小弟。
  4. 服務器4啓動,給自己投票,同時與之前啓動的服務器1,2,3交換信息,儘管服務器4的編號大,但之前服務器3已經勝出,所以服務器4只能成爲小弟。
  5. 服務器5啓動,後面的邏輯同服務器4成爲小弟。

Zookeeper特點

  • 順序一致性:從同一客戶端發起的事務請求,最終將會嚴格地按照順序被應用到 ZooKeeper 中去。
  • 原子性:所有事務請求的處理結果在整個集羣中所有機器上的應用情況是一致的,也就是說,要麼整個集羣中所有的機器都成功應用了某一個事務,要麼都沒有應用。
  • 單一系統映像:無論客戶端連到哪一個 ZooKeeper 服務器上,其看到的服務端數據模型都是一致的。
  • 可靠性:一旦一次更改請求被應用,更改的結果就會被持久化,直到被下一次更改覆蓋。

Zookeeper的功能(重要!!)

1. 命名服務

在zookeeper的文件系統裏創建一個目錄,即有唯一的path。在我們使用tborg無法確定上游程序的部署機器時即可與下游程序約定好path,通過path即能互相探索發現。

2. Zookeeper的配置管理

程序總是需要配置的,如果程序分散部署在多臺機器上,要逐個改變配置就變得困難。現在把這些配置全部放到zookeeper上去,保存在 Zookeeper 的某個目錄節點中,然後所有相關應用程序對這個目錄節點進行監聽,一旦配置信息發生變化,每個應用程序就會收到 Zookeeper 的通知,然後從 Zookeeper 獲取新的配置信息應用到系統中就好
在這裏插入圖片描述

3. Zookeeper集羣管理

所謂集羣管理無在乎兩點:是否有機器退出和加入、選舉master。

對於第一點,所有機器約定在父目錄GroupMembers下創建臨時目錄節點,然後監聽父目錄節點的子節點變化消息。一旦有機器掛掉,該機器與 zookeeper的連接斷開,其所創建的臨時目錄節點被刪除,所有其他機器都收到通知:某個兄弟目錄被刪除,於是,所有人都知道:它上船了。

新機器加入也是類似,所有機器收到通知:新兄弟目錄加入,highcount又有了,對於第二點,我們稍微改變一下,所有機器創建臨時順序編號目錄節點,每次選取編號最小的機器作爲master就好。
在這裏插入圖片描述

4. 分佈式鎖

這部分內容比較重要 在面試中屬於高頻考點,南國在之前的博客分佈式鎖入門及常見實現方式介紹講述過。

5. Zookeeper隊列管理

兩種類型的隊列:
1、同步隊列,當一個隊列的成員都聚齊時,這個隊列纔可用,否則一直等待所有成員到達。
2、隊列按照 FIFO 方式進行入隊和出隊操作。

第一類,在約定目錄下創建臨時目錄節點,監聽節點數目是否是我們要求的數目。
第二類,和分佈式鎖服務中的控制時序場景基本原理一致,入列有編號,出列按編號。

6. 數據複製

Zookeeper作爲一個集羣提供一致的數據服務,自然,它要在所有機器間做數據複製。數據複製的好處:
1、容錯:一個節點出錯,不致於讓整個系統停止工作,別的節點可以接管它的工作;
2、提高系統的擴展能力 :把負載分佈到多個節點上,或者增加節點來提高系統的負載能力;
3、提高性能:讓客戶端本地訪問就近的節點,提高用戶訪問速度。

從客戶端讀寫訪問的透明度來看,數據複製集羣系統分下面兩種:
1、寫主(WriteMaster) :對數據的修改提交給指定的節點。讀無此限制,可以讀取任何一個節點。這種情況下客戶端需要對讀與寫進行區別,俗稱讀寫分離;
2、寫任意(Write Any):對數據的修改可提交給任意的節點,跟讀一樣。這種情況下,客戶端對集羣節點的角色與變化透明。

對zookeeper來說,它採用的方式是寫任意。通過增加機器,它的讀吞吐能力和響應能力擴展性非常好,而寫,隨着機器的增多吞吐能力肯定下降(這也是它建立observer的原因),而響應能力則取決於具體實現方式,是延遲複製保持最終一致性,還是立即複製快速響應。

參考資料:
1.http://developer.51cto.com/art/201809/583184.htm
2.https://www.cnblogs.com/felixzh/p/5869212.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章