1. 程式人生 > >ZooKeeper概念與應用

ZooKeeper概念與應用

code 原子 最近修改 命名 觸發器 .com 樹狀 持久 創建

Zookeeper是開源的分布式協調服務,提供了分布式數據一致性的解決方案。

Zookeeper 可用作配置中心和分布式鎖服務,在 Dubbo、Kafka、Spark等分布式集群上得到廣泛應用。

ZNode

Zookeeper的數據模型為樹狀結構,樹的節點被稱作ZNode。

Zookeeper使用路徑來唯一標識ZNode,類似於Unix文件系統中的絕對路徑。路徑必須以/開頭,由Unicode字符串組成,如/myapp/master/0

每一個ZNode維護著三部分數據:

  • stat: 節點狀態信息,包括版本、更改時間、訪問控制等
  • data: 節點的內容數據,Zookeeper限制每個節點數據不超過1M。Zookeeper設計用來進行協調調度,請勿在其中存放大量數據。
  • children: 該ZNode的子節點。

每個節點都有獨立的訪問控制列表(Access Control List, ACL), 來控制用戶對本節點的訪問權限。

每個ZNode都維護著三個版本號:

  • dataVersion: 節點數據版本號
  • cversion: 子節點版本號
  • aclVersion: 節點訪問控制列表版本號

所有的寫操作都會使相應的版本號增加。寫操作必須指定要更新的ZNode的版本號,版本號不一致會導致寫入失敗。

Zxid

所有對Zookeeper狀態的改變都會產生一個Zxid(ZooKeeper Transaction Id),Zxid全局有序。

Zxid為標識事件發生的先後順序: 即事件A發生早於事件B,那麽事件A的Zxid定小於事件B的Zxid。

每個ZNode維護兩個Zxid:

  • cZxid: Znode創建
  • mZxid: Znode最近修改

Zxid是一個64位的數字, 高32位表示Zookeeper集群leader, 低32位表示邏輯順序。每次leader改變後, 新產生的Zxid高32位都會改變。

節點類型

Zookeeper中的節點分為兩種:

  • 臨時節點: 臨時節點依賴於創建節點的會話(Session), 一旦Session結束臨時節點會被自動刪除。臨時節點不允許擁有子節點
  • 永久節點: 永久節點生存期不依賴於客戶端會話,只有客戶端執行刪除操作時才會刪除。

Zookeeper 可以創建順序子節點,即創建子節點時在路徑結尾添加一個自增的32位 id, 該id在該節點的父節點下是唯一的。

Watch

Zookeeper 所有的讀操作getData(), getChildren()和 exists()都可以設置 Watch 觸發器。

Watch 觸發器是一次性的,當觸發器通知了一次狀態變化後消失,不會通知狀態的再次變化。

Zookeeper 與客戶端之間通過 Tcp Socket 進行通信, Zookeeper 會主動將時間通知客戶端。

Zookeeper 保證客戶端只有首先收到了Watch通知後,才會感知到它所設置監視的znode發生了變化。

Zookeeper 支持三種類型的watch:

  • exists: 被監視的Znode 創建、刪除、數據改變時被觸發
  • getData: 被監視的Znode 刪除、數據改變時被觸發
  • getChildren: 被監視的Znode 刪除、創建子節點、刪除子節點時被觸發

Zookeeper 應用

ZooKeeper 是具有較高一致性的分布式協調服務,它提供以下保證:

  • 原子性: 所有操作具有原子性
  • 分布式一致性: 從任意節點中讀取到的數據都是一致的
  • 順序一致性: 從一個客戶端來的更新請求會被順序執行
  • 持久性: 寫操作一旦成功,直到被覆蓋為止持續有效

Zookeeper 使用數據副本和崩潰恢復機制保證數據安全和集群高可用性。

Zookeeper 使用基於 Paxos 算法的 ZAB協議(Zookeeper Atomic Broadcast)進行寫操作,保證集群數據的一致性。

配置中心

我們可以將系統中通用配置信息寫入 ZNode 中,客戶端啟動時從 Zookeeper 獲取配置數據並監視配置節點的變化,當配置發生改變 Zookeeper 會通知所有的客戶端獲取最新數據,從而實現在線更新配置。

適合使用Zookeeper維護的配置通常:

  • 數據量較小
  • 在運行時動態發生變化
  • 各客戶端讀取到數據需要相同
  • 具有順序一致性,客戶端只要讀取到新版本的數據,此後就不能讀取到舊版本數據

當服務啟動時,服務提供者可以在Zookeeper的相應路徑下創建臨時節點,並在節點中寫入服務配置信息。服務關閉(崩潰)時,臨時節點自動刪除。

客戶端啟動時從 ZooKeeper 讀取服務提供者信息從而實現自動的服務發布/移除功能。

分布式鎖

Zookeeper 的臨時節點可以維護客戶端持有鎖的狀態,加鎖失敗的客戶端可以使用 Watch 機制監視鎖的釋放情況,實現阻塞等待加鎖。

Zookeeper 的順序節點可以實現一個簡單的隊列,可以利用此特性實現公平鎖。客戶端在鎖節點下創建順序子節點,持有最小子節點的客戶端成功加鎖,加鎖失敗的客戶端 Watch 前一個順序子節點,從而實現先到先得的公平鎖機制。

命名服務

ZooKeeper 的順序節點可以生成全局唯一ID, 我們可以利用該ID為服務命名。相對於UUID, 該名稱較短且可以保證絕不重復。

Master選舉

與分布式公平鎖應用類似,ZooKeeper 可以維護集群 Master。

集群中所有可以成為 Master 的進程都在 Zookeeper 中的指定路徑下創建順序子節點,持有最小子節點的進程成為Master。

集群中所有進程都 Watch 指定路徑下節點的情況,一旦發生變化則重新讀取最小子節點的持有者作為Master。

腦裂問題

傳統集群實現方案是運行一個備用Master節點,備用Master節點定期向主Master節點發送ping請求,若能及時收到主Master的ack響應則認為正常。

若Ack響應超時,備用Master則會取代原主Master成為新的集群主Master節點。

技術分享圖片

若響應超時因為主Master故障導致,備用Master成為新的主節點完全正常。

若超時因為主備 Master 節點間 ping-ack 網絡故障導致,那麽主Master工作正常,而備用Master卻誤認為主Master崩潰而進行取代,那麽集群中可能出現多個Master共存的故障(即腦裂故障)。

若使用 Zookeeper 維護 Master 信息,無論是因為主Master故障還是通信問題導致最小子節點被刪除,備用Master持有的節點都會成為最小子節點。

此時,所有客戶端都會受到通知並得知 Master 變更,保證集群中只有一個 Master。

當崩潰的Master恢復後,它將成為新的備用Master加入集群。

ZooKeeper 無法避免通信故障導致誤判 Master 狀態,但是可以保證在任何情況下集群中只有一個 Master 節點。

ZooKeeper概念與應用