一文了解 Zookeeper 基本原理與應用場景

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ā)都是一種鼓勵旺韭,期待得到您的認可 ?(^_-)

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氛谜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子区端,更是在濱河造成了極大的恐慌混蔼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件珊燎,死亡現(xiàn)場離奇詭異,居然都是意外死亡遵湖,警方通過查閱死者的電腦和手機悔政,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來延旧,“玉大人谋国,你說我怎么就攤上這事∏” “怎么了芦瘾?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長集畅。 經(jīng)常有香客問我近弟,道長,這世上最難降的妖魔是什么挺智? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任祷愉,我火速辦了婚禮,結果婚禮上赦颇,老公的妹妹穿的比我還像新娘二鳄。我一直安慰自己,他們只是感情好媒怯,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布订讼。 她就那樣靜靜地躺著,像睡著了一般扇苞。 火紅的嫁衣襯著肌膚如雪欺殿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天鳖敷,我揣著相機與錄音祈餐,去河邊找鬼。 笑死哄陶,一個胖子當著我的面吹牛帆阳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蜒谤,長吁一口氣:“原來是場噩夢啊……” “哼山宾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鳍徽,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤资锰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后阶祭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绷杜,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年濒募,在試婚紗的時候發(fā)現(xiàn)自己被綠了鞭盟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡瑰剃,死狀恐怖齿诉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晌姚,我是刑警寧澤粤剧,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站挥唠,受9級特大地震影響抵恋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宝磨,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一馋记、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧懊烤,春花似錦梯醒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壁肋,卻和暖如春号胚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浸遗。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工猫胁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跛锌。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓弃秆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子菠赚,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容