分布式協調服務之Zookeeper


1. 認識Zookeeper

  ZooKeeper是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、命名服務、分布式同步、組服務等。  

  Zookeeper 作為一個分布式的服務框架,主要用來解決分布式集群中應用系統的一致性問題,它能提供基於類似於文件系統的目錄節點樹方式的數據存儲, Zookeeper 作用主要是用來維護和監控存儲的數據的狀態變化,通過監控這些數據狀態的變化,從而達到基於數據的集群管理。

  簡單的說,Zookeeper=文件系統+通知機制。

 

2. Zookeeper的樹狀結構

  

  /zookeeper節點和/controller_epoch節點是zookeeper自帶的默認節點。

2.1. ZNode

  Zookeeper有四種類型的znode:
  1). PERSISTENT-持久化目錄節點: 客戶端與zookeeper斷開連接后, 該節點依舊存在。
  2). PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點: 客戶端與zookeeper斷開連接后,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號。
  3). EPHEMERAL-臨時目錄節點: 客戶端與zookeeper斷開連接后,該節點被刪除。
  4). EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點: 客戶端與zookeeper斷開連接后,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號。

  順序編號:共有10位長的數字,從0000000000開始,每增加一個節點,末位加1。

  每一個Znode都由三部分組成:

  data:與該Znode關聯的數據。

  stat:狀態信息, 描述此Znode的版本時間權限等信息。

  children:該Znode下的子節點。

 2.1.1 stat

  cZxid:這是導致創建znode更改的事務ID。
  mZxid:這是最后修改znode更改的事務ID。
  pZxid:這是用於添加或刪除子節點的znode更改的事務ID。
  ctime:表示從1970-01-01T00:00:00Z開始以毫秒為單位的znode創建時間。
  mtime:表示從1970-01-01T00:00:00Z開始以毫秒為單位的znode最近修改時間。
  dataVersion:表示對該znode的數據所做的更改次數。
  cversion:這表示對此znode的子節點進行的更改次數。
  aclVersion:表示對此znode的ACL進行更改的次數。
  ephemeralOwner:如果znode是ephemeral類型節點,則這是znode所有者的 session ID。 如果znode不是ephemeral節點,則該字段設置為零。
  dataLength:這是znode數據字段的長度。
  numChildren:這表示znode的子節點的數量。

2.1.2. ACL

  概述:傳統的文件系統中,ACL分為兩個維度,一個是屬組,一個是權限,子目錄/文件默認繼承父目錄的ACL。而在Zookeeper中,node的ACL是沒有繼承關系的,是獨立控制的。Zookeeper的ACL,可以從三個維度來理解:一是scheme; 二是user; 三是permission,通常表示為scheme:id:permissions, 下面從這三個方面分別來介紹:

  1). scheme: scheme對應於采用哪種方案來進行權限管理,zookeeper實現了一個pluggable的ACL方案,可以通過擴展scheme,來擴展ACL的機制。

  zookeeper-3.4.4缺省支持下面幾種scheme:

  world: 它下面只有一個id, 叫anyone, world:anyone代表任何人,zookeeper中對所有人有權限的結點就是屬於world:anyone的
  auth: 它不需要id, 只要是通過authentication的user都有權限(zookeeper支持通過kerberos來進行authencation, 也支持username/password形式的authentication)
  digest: 它對應的id為username:BASE64(SHA1(password)),它需要先通過username:password形式的authentication
  ip: 它對應的id為客戶機的IP地址,設置的時候可以設置一個ip段,比如ip:192.168.1.0/16, 表示匹配前16個bit的IP段
  super: 在這種scheme情況下,對應的id擁有超級權限,可以做任何事情(cdrwa)

  另外,zookeeper-3.4.4的代碼中還提供了對sasl的支持,不過缺省是沒有開啟的,需要配置才能啟用。

  sasl: sasl的對應的id,是一個通過sasl authentication用戶的id,zookeeper-3.4.4中的sasl authentication是通過kerberos來實現的,也就是說用戶只有通過了kerberos認證,才能訪問它有權限的node。

  2). id: id與scheme是緊密相關的,具體的情況在上面介紹scheme的過程都已介紹,這里不再贅述。

  3). permission: zookeeper目前支持下面一些權限:

  CREATE(c): 創建權限,可以在在當前node下創建child node
  DELETE(d): 刪除權限,可以刪除當前的node
  READ(r): 讀權限,可以獲取當前node的數據,可以list當前node所有的child nodes
  WRITE(w): 寫權限,可以向當前node寫數據
  ADMIN(a): 管理權限,可以設置當前node的permission

 

3. NameService命名服務

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

  這個主要是作為分布式命名服務,通過調用Zookeeper的create node api,能夠很容易創建一個全局唯一的path,這個path就可以作為一個名稱。

 

4. Configuration 配置管理

  把需要增加的配置全部放到Zookeeper上去,保存在 Zookeeper的某個目錄節點中,然后所有相關應用程序對這個目錄節點進行監聽,一旦配置信息發生變化,每個應用程序就會收到 Zookeeper 的通知,然后從 Zookeeper 獲取新的配置信息應用到系統中就完成了配置管理。

5. GroupMembers 集群管理

  所謂集群管理無外乎兩點:是否有機器加入和退出、選舉master。
  對於第一點,所有機器約定在父目錄GroupMembers下創建臨時目錄節點,然后監聽父目錄節點的子節點變化消息。一旦有機器掛掉,該機器與 zookeeper的連接斷開,其所創建的臨時目錄節點被刪除,所有其他機器都收到通知:某個兄弟目錄被刪除,於是,所有人都知道了。新機器加入也是類似,所有機器收到通知:新兄弟目錄加入,highcount又有了。
  對於第二點,所有機器創建臨時順序編號目錄節點,通過master選舉算法選舉出來。

 

6. Zookeeper的三個角色及狀態

  1). Leader

  Leader服務器是整個zookeeper集群工作機制中的核心,其主要工作有以下兩個:

          a. 事物請求的唯一調度和處理者,保證集群事務處理的順序性。

          b. 集群內部各個服務器的調度者。

  2). Follower

  從角色名字可以看出,Follower服務器是zookeeper集群狀態的跟隨者,其主要工作有以下三個:

    a. 處理客戶端非事物請求,轉發事物請求給Leader服務器。

    b. 參與事務請求Proposal的投票。

    c. 參與Leader選舉投票。

  3). Observer

  和Follower唯一的區別在於,Observer不參與任何形式的投票,包括事物請求Proposal的投票和Leader選舉投票。

  簡單地講,Observer服務器只提供非事物服務,通常用於在不影響集群事務處理能力的前提下提升集群的非事物處理能力。

  

  節點狀態

  Zookeeper節點有四種狀態:Looking、Following、Leading、Observing

  Looking:尋找Leader狀態,當Server處於該狀態時,此Server會認為當前集群中沒有Leader,需要進入Leader選舉狀態。

  Following: 跟隨者狀態,表明該Server角色為Follower。

  Leading: 領導者狀態,表明當前服務器角色是Leader。

  Observing: 觀察者狀態,表明當前服務器角色是Observer。

 

7. 選舉算法

  Zookeeper中有三種選舉算法,分別是LeaderElection(基於basic paxos實現),FastLeaderElection,AuthLeaderElection

  FastLeaderElection和AuthLeaderElection(都是基於fast paxos實現)是類似的選舉算法,唯一區別是后者加入了認證信息,FastLeaderElection比LeaderElection更高效。

  basic paxos流程:

  1 .選舉線程由當前Server發起選舉的線程擔任,其主要功能是對投票結果進行統計,並選出推薦的Server;
  2 .選舉線程首先向所有Server發起一次詢問(包括自己);
  3 .選舉線程收到回復后,驗證是否是自己發起的詢問(驗證zxid是否一致),然后獲取對方的id(myid),並存儲到當前詢問對象列表中,最后獲取對方提議的leader相關信息(id,zxid),並將這些信息存儲到當次選舉的投票記錄表中;
  4. 收到所有Server回復以后,就計算出zxid最大的那個Server,並將這個Server相關信息設置成下一次要投票的Server;
  5. 線程將當前zxid最大的Server設置為當前Server要推薦的Leader,如果此時獲勝的Server獲得n/2 + 1的Server票數, 設置當前推薦的leader為獲勝的Server,將根據獲勝的Server相關信息設置自己的狀態,否則,繼續這個過程,直到leader被選舉出來。
  通過流程分析我們可以得出:要使Leader獲得多數Server的支持,則Server總數必須是奇數2n+1,且存活的Server的數目不得少於n+1.


  fast paxos流程:

  在選舉過程中,某Server首先向所有Server提議自己要成為leader,當其它Server收到提議以后,解決epoch和 zxid的沖突,並接受對方的提議,然后向對方發送接受提議完成的消息,重復這個流程,最后一定能選舉出Leader。

  

8. Watcher

  Watcher是Zookeeper用來實現distribute lock, distribute configure, distribute queue等應用的主要手段。要監控data_tree上的任何節點的變化(節點本身的增加,刪除,數據修改,以及子節點的變化)都可以在獲取該數據時注冊一個Watcher,這有很像Listener模式。一旦該節點數據變化,Follower會發送一個notification response,client收到notification響應,則會查找對應的Watcher並回調他們。

  Client可以在某個ZNode上設置一個Watcher,來Watch該ZNode上的變化。如果該ZNode上有相應的變化,就會觸發這個Watcher,把相應的事件通知給設置Watcher的Client。需要注意的是,ZooKeeper中的Watcher是一次性的,即觸發一次就會被取消,如果想繼續Watch的話,需要客戶端重新設置Watcher。

  atomic broadcasts原子廣播

  Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分 別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和 leader的狀態同步以后,恢復模式就結束了。狀態同步保證了leader和Server具有相同的系統狀態。

  

  ZooKeeper Watcher 特性總結

  1). 注冊只能確保一次消費
  無論是服務端還是客戶端,一旦一個 Watcher 被觸發,ZooKeeper 都會將其從相應的存儲中移除。因此,開發人員在 Watcher 的使用上要記住的一點是需要反復注冊。這樣的設計有效地減輕了服務端的壓力。如果注冊一個 Watcher 之后一直有效,那么針對那些更新非常頻繁的節點,服務端會不斷地向客戶端發送事件通知,這無論對於網絡還是服務端性能的影響都非常大。

  2). 客戶端串行執行
  客戶端 Watcher 回調的過程是一個串行同步的過程,這為我們保證了順序,同時,需要開發人員注意的一點是,千萬不要因為一個 Watcher 的處理邏輯影響了整個客戶端的 Watcher 回調。

  3). 輕量級設計
  WatchedEvent 是 ZooKeeper 整個 Watcher 通知機制的最小通知單元,這個數據結構中只包含三部分的內容:通知狀態、事件類型和節點路徑。也就是說,Watcher 通知非常簡單,只會告訴客戶端發生了事件,而不會說明事件的具體內容。例如針對 NodeDataChanged 事件,ZooKeeper 的 Watcher 只會通知客戶指定數據節點的數據內容發生了變更,而對於原始數據以及變更后的新數據都無法從這個事件中直接獲取到,而是需要客戶端主動重新去獲取數據,這也是 ZooKeeper 的 Watcher 機制的一個非常重要的特性。

 

9. 設計目的

  1). 最終一致性:client不論連接到哪個Server,展示給它都是同一個視圖,這是zookeeper最重要的性能。
  2). 可靠性:具有簡單、健壯、良好的性能,如果消息m被到一台服務器接受,那么它將被所有的服務器接受。
  3). 實時性:Zookeeper保證客戶端將在一個時間間隔范圍內獲得服務器的更新信息,或者服務器失效的信息。但由於網絡延時等原因,Zookeeper不能保證兩個客戶端能同時得到剛更新的數據,如果需要最新數據,應該在讀數據之前調用sync()接口。
  4). 等待無關(wait-free):慢的或者失效的client不得干預快速的client的請求,使得每個client都能有效的等待。
  5). 原子性:更新只能成功或者失敗,沒有中間狀態。
  6). 順序性:包括全局有序和偏序兩種:全局有序是指如果在一台服務器上消息a在消息b前發布,則在所有Server上消息a都將在消息b前被發布;偏序是指如果一個消息b在消息a后被同一個發送者發布,a必將排在b前面

 

10. 典型使用場景

  ZooKeeper是一個高可用的分布式數據管理與系統協調框架。基於對Paxos算法的實現,使該框架保證了分布式環境中數據的強一致性,也正是基於這樣的特性,使得zookeeper能夠應用於很多場景。

  1). 數據發布與訂閱

  發布與訂閱即所謂的配置管理,顧名思義就是將數據發布到zk節點上,供訂閱者動態獲取數據,實現配置信息的集中式管理和動態更新。例如全局的配置信息,地址列表等就非常適合使用。

  1>. 索引信息和集群中機器節點狀態存放在zk的一些指定節點,供各個客戶端訂閱使用。

  2>. 系統日志(經過處理后的)存儲,這些日志通常2-3天后被清除。

  3>. 應用中用到的一些配置信息集中管理,在應用啟動的時候主動來獲取一次,並且在節點上注冊一個Watcher,以后每次配置有更新,實時通知到應用,獲取最新配置信息。
  4>. 業務邏輯中需要用到的一些全局變量,比如一些消息中間件的消息隊列通常有個offset,這個offset存放在zk上,這樣集群中每個發送者都能知道當前的發送進度。
  5>. 系統中有些信息需要動態獲取,並且還會存在人工手動去修改這個信息。以前通常是暴露出接口,例如JMX接口,有了zk后,只要將這些信息存放到zk節點上即可。


  2). 分布通知/協調

  ZooKeeper 中特有watcher注冊與異步通知機制,能夠很好的實現分布式環境下不同系統之間的通知與協調,實現對數據變更的實時處理。使用方法通常是不同系統都對 ZK上同一個znode進行注冊,監聽znode的變化(包括znode本身內容及子節點的),其中一個系統update了znode,那么另一個系統能 夠收到通知,並作出相應處理。

  1>. 另一種心跳檢測機制:檢測系統和被檢測系統之間並不直接關聯起來,而是通過zk上某個節點關聯,大大減少系統耦合。

  2>. 另一種系統調度模式:某系統有控制台和推送系統兩部分組成,控制台的職責是控制推送系統進行相應的推送工作。管理人員在控制台作的一些操作,實際上是修改 了ZK上某些節點的狀態,而zk就把這些變化通知給他們注冊Watcher的客戶端,即推送系統,於是,作出相應的推送任務。

  3>. 另一種工作匯報模式:一些類似於任務分發系統,子任務啟動后,到zk來注冊一個臨時節點,並且定時將自己的進度進行匯報(將進度寫回這個臨時節點),這樣任務管理者就能夠實時知道任務進度。

  總之,使用zookeeper來進行分布式通知和協調能夠大大降低系統之間的耦合。


  3). 分布式鎖

  分布式鎖:這個主要得益於ZooKeeper為我們保證了數據的強一致性,即用戶只要完全相信每時每刻,zk集群中任意節點(一個zk server)上的相同znode的數據是一定是相同的。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序。
  保持獨占:就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過create znode的方式來實現。所有客戶端都去創建 /distribute_lock 節點,最終成功創建的那個客戶端也即擁有了這把鎖。
  控制時序:就是所有視圖來獲取這個鎖的客戶端,最終都是會被安排執行,只是有個全局時序了。做法和上面基本類似,只是這里 /distribute_lock 已經預先存在,客戶端在它下面創建臨時有序節點(這個可以通過節點的屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。Zk的父節點(/distribute_lock)維持一份sequence,保證子節點創建的時序性,從而也形成了每個客戶端的全局時序。


  4). 集群管理

  1>. 集群機器監控:這通常用於那種對集群中機器狀態,機器在線率有較高要求的場景,能夠快速對集群中機器變化作出響應。這樣的場景中,往往有一個監控系統,實時檢測集群機器是否存活。過去的做法通常是:監控系統通過某種手段(比如ping)定時檢測每個機器,或者每個機器自己定時向監控系統匯報“我還活着”。 這種做法可行,但是存在兩個比較明顯的問題:1. 集群中機器有變動的時候,牽連修改的東西比較多。2. 有一定的延時。

  利用ZooKeeper有兩個特性,就可以實時另一種集群機器存活性監控系統:a. 客戶端在節點 x 上注冊一個Watcher,那么如果 x 的子節點變化了,會通知該客戶端。b. 創建EPHEMERAL類型的節點,一旦客戶端和服務器的會話結束或過期,那么該節點就會消失。

  2>. Master選舉則是zookeeper中最為經典的使用場景了。
在分布式環境中,相同的業務應用分布在不同的機器上,有些業務邏輯(例如一些耗時的計算,網絡I/O處理),往往只需要讓整個集群中的某一台機器進行執行, 其余機器可以共享這個結果,這樣可以大大減少重復勞動,提高性能,於是這個master選舉便是這種場景下的碰到的主要問題。
  利用ZooKeeper的強一致性,能夠保證在分布式高並發情況下節點創建的全局唯一性,即:同時有多個客戶端請求創建 /currentMaster 節點,最終一定只有一個客戶端請求能夠創建成功。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM