Zookeeper 是一個高性能缎玫、高可靠的分布式協(xié)調(diào)系統(tǒng),是 Google Chubby 的一個開源實現(xiàn)努释,目前在分布式系統(tǒng)碘梢、大數(shù)據(jù)領域中使用非常廣泛。本文將介紹 Zookeeper 集群架構伐蒂、數(shù)據(jù)模型煞躬、監(jiān)聽機制,以及Zookeeper典型的應用場景等逸邦。
1. Zookeeper 集群角色
首先介紹下 Zookeeper 集群恩沛,一個 Zookeeper 集群通常由一組機器組成,一般3~5臺集群就可以組成一個 Zookeeper 集群缕减。集群拓撲圖基本如下:
Zookeeper 集群中每一個節(jié)點都會在內(nèi)存中維護當前的節(jié)點狀態(tài)雷客,并且彼此之間保持著通信。這里說明一點桥狡,只要集群中存在過半的節(jié)點正常工作搅裙,整個集群就能夠?qū)ν馓峁┓铡?/p>
如上圖,在 Zookeeper 集群中裹芝,有 Leader部逮、Follower 和 Observer 三種類型的角色。
Leader
Leader 節(jié)點整個 Zookeeper 集群工作機制中的核心嫂易,主要工作是處理客戶端的讀寫請求兄朋,及集群內(nèi)部各服務的調(diào)度。注意只有 leader 能夠處理寫請求怜械。
Follower
處理客戶端的讀請求颅和,將寫請求轉(zhuǎn)發(fā)給 leader。參與 leader 選舉投票等缕允。
Observer
這是自 Zookeeper 3.3.0 版本引入的一個新的角色峡扩,主要是為了解決大規(guī)模 Server 場景下因 leader 選舉投票成本增加導致寫性能下降的問題。Observer 的工作原理和 follower 基本一致障本。處理客戶端的讀請求教届,將寫請求轉(zhuǎn)發(fā)給leader。和 follower 唯一的區(qū)別在于彼绷,Observer不參與任何形式的選舉,包括 leader 選舉茴迁。一般而言寄悯,中小型規(guī)模的 Zookeeper 集群中只包含 leader 和 follower 兩個角色,這容易讓我們忽略 observer 角色的存在堕义。配置一個節(jié)點為 observer 也很簡單猜旬,只需如下兩步:
# 在observer節(jié)點的配置文件中添加如下配置
peerType=observer
# 在每個節(jié)點的配置文件中脆栋,給observer節(jié)點添加:observer標識
# 例如:
server.1:localhost:2181:3181:observer
至此,相信你對 Zookeeper 的集群架構與相關角色有了一定認識洒擦。
2. Zookeeper 數(shù)據(jù)模型
Zookeeper 的數(shù)據(jù)模型是一棵類似 Unix 文件系統(tǒng)的 ZNode Tree 即 ZNode 樹椿争,但是沒有引入傳統(tǒng)文件系統(tǒng)的目錄或者文件等概念,而是使用了稱為 “數(shù)據(jù)節(jié)點” 的概念熟嫩,術語叫做 ZNode译柏。ZNode 是 Zookeeper 存儲數(shù)據(jù)的最小單元踩晶,每個 ZNode 可以保存數(shù)據(jù),也可以掛載子節(jié)點,其中根節(jié)點是 /炎咖。示意圖如下:
使用過 Zookeeper 的同學應該都知道,Zookeeper 主要提供了兩個核心功能:
- 管理(存儲酿联、讀认艚搿)客戶端提交的數(shù)據(jù);
- 為客戶端提供數(shù)據(jù)節(jié)點的監(jiān)聽服務逗鸣;
這里就涉及到 Zookeeper 的兩個重要特性合住,就是它的 ZNode 模型與 Watcher 機制。
ZNode 模型
前面講到 Zookeeper 是由數(shù)據(jù)節(jié)點 ZNode 構成的撒璧,Zookeeper 中的每個數(shù)據(jù)節(jié)點都是有生命周期的透葛,其生命周期的長短取決于 ZNode 的節(jié)點類型。ZNode 根據(jù)其生命周期和特點可分為 4 類沪悲。
分別是:
持久性節(jié)點(PERSISTENT):客戶端與 Zookeeper 斷開會話后获洲,該節(jié)點依舊存在,直到執(zhí)行刪除操作才會清除節(jié)點殿如。
持久性順序節(jié)點(PERSISTENT_SEQUENTIAL):另一種持久節(jié)點贡珊,Zookeeper 會給該節(jié)點名稱加上一個數(shù)字后綴,進行順序編號涉馁。
臨時節(jié)點(EPHEMERAL):節(jié)點的生命周期和客戶端的會話綁定在一起门岔,客戶端與 Zookeeper 斷開會話后,該節(jié)點就會被自動刪除烤送。各個場景中很多都是利用 Zookeeper 臨時節(jié)點這個特性的寒随。
臨時順序節(jié)點(EPHEMERAL_SEQUENTIAL):概念和上面類似,Zookeeper 也會給該節(jié)點進行順序編號帮坚。
前面提及了 ZNode 是存儲數(shù)據(jù)的最小單元妻往,除了存儲用戶數(shù)據(jù)外,ZNode 還有以下特點:
包含 ZNode 修改/訪問的時間试和、事務id(zxid)讯泣,ACL 權限、版本等狀態(tài)信息阅悍;
所有的事務請求在 ZNode 端都是順序和原子性的好渠;
數(shù)據(jù)主要存儲在內(nèi)存中昨稼,磁盤中保存事務日志、快照數(shù)據(jù)等拳锚;
Watcher 機制
Watcher 機制也稱監(jiān)聽機制假栓,它是 Zookeeper 的關鍵特性,是通過 ZooKeeper 實現(xiàn)分布式發(fā)布/訂閱霍掺、分布式鎖匾荆、集群管理等功能的基礎。
如上圖所示抗楔,Zookeeper 允許客戶端向服務端注冊一個 Watcher 監(jiān)聽器棋凳,當服務端的一些指定事件觸發(fā)了該監(jiān)聽,比如節(jié)點創(chuàng)建连躏、刪除剩岳,節(jié)點數(shù)據(jù)變更等事件,Zookeeper 就會向注冊了監(jiān)聽器的客戶端發(fā)送相應的事件通知入热。
3. 代碼演示 Zookeeper 監(jiān)聽器
接下來我們看一下通過 Zookeeper 原生的客戶端 API拍棕,創(chuàng)建 ZNode 數(shù)據(jù)節(jié)點,然后演示下 Zookeeper 監(jiān)聽器的基本使用勺良。
引入依賴
首先绰播,當前有一個包含3個節(jié)點的 Zookeeper 集群,我們根據(jù) Zookeeper 版本引入了相應依賴尚困,如下
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.5</version>
</dependency>
演示代碼
- 創(chuàng)建 ZNode
private final String ZK_ADDRS = "server01:2181,server02:2181,server03:2181";
private final int SESSION_TIMEOUT = 5000;
private String znodePath = "/my_node";
@Test
public void createZNode() throws IOException, KeeperException, InterruptedException {
//創(chuàng)建zookeeper客戶端
ZooKeeper zkClient = new ZooKeeper(ZK_ADDRS, SESSION_TIMEOUT, watchedEvent -> {});
//判斷節(jié)點是否存在
Stat exist = zkClient.exists(znodePath, false);
if (exist == null){
//創(chuàng)建一個持久節(jié)點并寫入數(shù)據(jù)蠢箩,完全放開acl權限
zkClient.create(znodePath, "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
//關閉zookeeper連接
zkClient.close();
}
(可左右滑動)
執(zhí)行完這個單元測試后,我們通過命令行在服務端查看一下該數(shù)據(jù)節(jié)點:
[zk: localhost:2181(CONNECTED) 48] get /my_node
123
cZxid = 0xdb6439ef2
ctime = Fri Feb 27 21:08:09 CST 2020
mZxid = 0xdb6439ef2
mtime = Fri Feb 27 21:08:09 CST 2020
pZxid = 0xdb6439ef2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
- 刪除 ZNode 節(jié)點事甜,并監(jiān)聽該節(jié)點的刪除動作
@Test
public void TestWatcher() throws IOException, KeeperException, InterruptedException {
//創(chuàng)建zookeeper客戶端谬泌,并注冊一個監(jiān)聽器
ZooKeeper zkClient = new ZooKeeper(ZK_ADDRS, SESSION_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
//監(jiān)聽指定節(jié)點刪除事件
if (watchedEvent.getType() == Event.EventType.NodeDeleted &&
watchedEvent.getPath().equals(znodePath)){
log.info(String.format("注意:ZNode '%s' is deleted !", znodePath));
}
}
});
//判斷節(jié)點是否存在,同時注冊了一個 watcher
Stat exist = zkClient.exists(znodePath, true);
if (exist != null){
//刪除節(jié)點
zkClient.delete(znodePath, -1);
}
//關閉zookeeper連接
zkClient.close();
}
(可左右滑動)
代碼執(zhí)行后逻谦,可以看到控制臺打印出了我們的日志:
21:41:07.870 [main-EventThread] INFO xxx - 注意:ZNode '/my_node' is deleted !
服務端查看該節(jié)點也已經(jīng)不存在了:
[zk: localhost:2181(CONNECTED) 50] get /my_node
Node does not exist: /my_node
這里我們簡單演示了下 Zookeeper 原始 API掌实、監(jiān)聽器的使用,希望通過這個簡單的demo邦马,我們能對 Zookeeper 監(jiān)聽器有一個比較直觀的認識贱鼻。
4. Zookeeper 應用場景
Zookeeper 在分布式系統(tǒng)、大數(shù)據(jù)領域里應用廣泛滋将,這里總結了 8 個典型的應用場景:
數(shù)據(jù)發(fā)布/訂閱
即所謂的配置管理或配置中心邻悬,拓撲圖如下:
通常在分布式系統(tǒng)或集群中,所以節(jié)點的配置應該一致随闽,比如Hadoop集群父丰,要求對配置的修改,能夠快速同步到各個節(jié)點中橱脸,可以通過 Zookeeper 實現(xiàn):
將配置信息寫入 ZooKeeper 的一個 ZNode 中础米;
各個節(jié)點在啟動階段從 Zookeeper 中獲取配置,并注冊一個數(shù)據(jù)變更的 Watcher 監(jiān)聽器添诉;
當 ZNode 中的數(shù)據(jù)被修改屁桑,ZooKeeper 將通知各個客戶端節(jié)點,節(jié)點收到通知后進行配置更新栏赴;
負載均衡
負載均衡通常是一種動態(tài)的服務配置蘑斧,拓撲圖:
通常包含兩部分:
服務注冊,服務提供者啟動時會在某一個根 ZNode 節(jié)點下創(chuàng)建屬于自己的子節(jié)點须眷,并寫入一些服務信息 比如IP:Port信息竖瘾;
服務解析,服務使用者在請求服務時會先獲取根 ZNode 節(jié)點的子節(jié)點列表花颗,即服務列表捕传,然后通過一定的負載均衡算法 比如hash選取一個服務訪問;
命名服務
又稱 nameservice扩劝,這是比較常見的場景庸论,Zookeeper 的命令服務主要有兩個方向的應用:
提供類似 JNDI 的功能:就是把各種服務的名稱,地址及其他信息放到 Zookeeper 中棒呛,使用時去讀取聂示,實現(xiàn)資源的定位和使用;
利用 Zookeeper 順序節(jié)點的特性簇秒,生成分布式的全局唯一 ID鱼喉;
分布式協(xié)調(diào)/通知
主要是利用了 Zookeeper Watcher 的注冊與異步通知機制,通常的做法是不同客戶端都對 Zookeeper 的一個數(shù)據(jù)節(jié)點進行 Watcher 注冊趋观,監(jiān)聽數(shù)據(jù)的變化扛禽,當數(shù)據(jù)節(jié)點發(fā)生變化時,所有訂閱的客戶端都能接到通知并做相應處理拆内。常見場景比如:
Master 節(jié)點定期檢測 Slave 節(jié)點的狀態(tài)旋圆,類似于心跳檢測機制;
信息推送麸恍,相當于一個發(fā)布訂閱系統(tǒng)灵巧,和第一個場景類似;
集群管理
主要包括兩部分功能
記錄當前集群中有多少個節(jié)點在工作抹沪,以及節(jié)點的運行狀態(tài)刻肄;
對集群中的節(jié)點進行上下線方面的操作;
Master 選舉
Master 選舉是一個分布式系統(tǒng)中非常常見的場景融欧,這里是利用 Zookeeper 的強一致性敏弃,保證只有一個客戶端能夠創(chuàng)建節(jié)點成功。
分布式鎖
不同節(jié)點上的服務噪馏,可能需要同時訪問一個資源麦到,這事可能需要一把分布式鎖绿饵。使用 Zookeeper 實現(xiàn)分布式鎖主要基于以下特性:
ZooKeeper 的強一致性,保證只有一個客戶端能夠創(chuàng)建鎖成功瓶颠。
鎖的獨占性拟赊,創(chuàng)建 ZNode 成功的客戶端才能得到鎖,其他客戶端只能等待粹淋,當客戶端用完釋放鎖時吸祟,其他客戶端再次嘗試創(chuàng)建 ZNode,獲取分布式鎖桃移。
分布式隊列
利用 Zookeeper 主要能夠?qū)崿F(xiàn)兩種分布式隊列:
當一個隊列的成員都聚齊時屋匕,這個隊列才可用,否則一直等待所有成員到達借杰,這種是同步隊列过吻。 比如一個 job 由多個 task 組成,只有所有 task 完成后蔗衡,job 才運行完成疮装,可為 job 創(chuàng)建一個 /job 目錄,然后在該目錄下粘都,為每個完成的 task 創(chuàng)建一個臨時的 ZNode廓推,一旦臨時節(jié)點數(shù)目達到 task 總數(shù),則表明 job 運行完成翩隧。
利用 Zookeeper 的臨時順序節(jié)點特性樊展,實現(xiàn) FIFO 即先進先出的隊列。
5. 總結
本文介紹了 Zookeeper 的集群架構堆生,ZNode 數(shù)據(jù)模型专缠,Watcher 監(jiān)聽機制,以及 Zookeeper 的典型應用場景淑仆。Zookeeper 在分布式系統(tǒng)應用非常廣泛涝婉,主流的大數(shù)據(jù)組件比如HDFS、HBase蔗怠、Kafka等也依靠 Zookeeper 做協(xié)調(diào)服務墩弯。通過本文的介紹,相信我們對 Zookeeper 有了進一步的掌握寞射。
往期文章精選:
1渔工、如何快速全面掌握Kafka?5000字吐血整理
2桥温、一文讀懂 HBase 核心原理與應用場景
3引矩、京東JDHBase異地多活實踐
4、美團點評基于 Flink 的實時數(shù)倉平臺實踐
如果您喜歡這篇文章,點【在看】與轉(zhuǎn)發(fā)都是一種鼓勵旺韭,期待得到您的認可 ?(^_-)