日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

一文教你掌握 ZooKeeper 核心知识

發(fā)布時(shí)間:2023/12/2 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文教你掌握 ZooKeeper 核心知识 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ZooKeeper 是一個(gè)分布式協(xié)調(diào)服務(wù)?,由 Apache 進(jìn)行維護(hù)。

ZooKeeper 可以視為一個(gè)高可用的文件系統(tǒng)。

ZooKeeper 可以用于發(fā)布/訂閱、負(fù)載均衡、命令服務(wù)、分布式協(xié)調(diào)/通知、集群管理、Master 選舉、分布式鎖和分布式隊(duì)列等功能 。

一、ZooKeeper 簡(jiǎn)介

1.1 ZooKeeper 是什么

ZooKeeper 是 Apache 的頂級(jí)項(xiàng)目。ZooKeeper 為分布式應(yīng)用提供了高效且可靠的分布式協(xié)調(diào)服務(wù),提供了諸如統(tǒng)一命名服務(wù)、配置管理和分布式鎖等分布式的基礎(chǔ)服務(wù)。在解決分布式數(shù)據(jù)一致性方面,ZooKeeper 并沒有直接采用 Paxos 算法,而是采用了名為 ZAB 的一致性協(xié)議。

ZooKeeper 主要用來(lái)解決分布式集群中應(yīng)用系統(tǒng)的一致性問題,它能提供基于類似于文件系統(tǒng)的目錄節(jié)點(diǎn)樹方式的數(shù)據(jù)存儲(chǔ)。但是 ZooKeeper 并不是用來(lái)專門存儲(chǔ)數(shù)據(jù)的,它的作用主要是用來(lái)維護(hù)和監(jiān)控存儲(chǔ)數(shù)據(jù)的狀態(tài)變化。通過監(jiān)控這些數(shù)據(jù)狀態(tài)的變化,從而可以達(dá)到基于數(shù)據(jù)的集群管理。

很多大名鼎鼎的框架都基于 ZooKeeper 來(lái)實(shí)現(xiàn)分布式高可用,如:Dubbo、Kafka 等。

1.2 ZooKeeper 的特性

ZooKeeper 具有以下特性:

  • 順序一致性:所有客戶端看到的服務(wù)端數(shù)據(jù)模型都是一致的;從一個(gè)客戶端發(fā)起的事務(wù)請(qǐng)求,最終都會(huì)嚴(yán)格按照其發(fā)起順序被應(yīng)用到 ZooKeeper 中。具體的實(shí)現(xiàn)可見下文:原子廣播。

  • 原子性:所有事務(wù)請(qǐng)求的處理結(jié)果在整個(gè)集群中所有機(jī)器上的應(yīng)用情況是一致的,即整個(gè)集群要么都成功應(yīng)用了某個(gè)事務(wù),要么都沒有應(yīng)用。實(shí)現(xiàn)方式可見下文:事務(wù)。

  • 單一視圖:無(wú)論客戶端連接的是哪個(gè) Zookeeper 服務(wù)器,其看到的服務(wù)端數(shù)據(jù)模型都是一致的。

  • 高性能:ZooKeeper 將數(shù)據(jù)全量存儲(chǔ)在內(nèi)存中,所以其性能很高。需要注意的是:由于 ZooKeeper 的所有更新和刪除都是基于事務(wù)的,因此 ZooKeeper 在讀多寫少的應(yīng)用場(chǎng)景中有性能表現(xiàn)較好,如果寫操作頻繁,性能會(huì)大大下滑。

  • 高可用:ZooKeeper 的高可用是基于副本機(jī)制實(shí)現(xiàn)的,此外 ZooKeeper 支持故障恢復(fù),可見下文:選舉 Leader。

1.3 ZooKeeper 的設(shè)計(jì)目標(biāo)

  • 簡(jiǎn)單的數(shù)據(jù)模型

  • 可以構(gòu)建集群

  • 順序訪問

  • 高性能

二、ZooKeeper 核心概念

2.1? 數(shù)據(jù)模型

ZooKeeper 的數(shù)據(jù)模型是一個(gè)樹形結(jié)構(gòu)的文件系統(tǒng)。

樹中的節(jié)點(diǎn)被稱為 znode,其中根節(jié)點(diǎn)為?/,每個(gè)節(jié)點(diǎn)上都會(huì)保存自己的數(shù)據(jù)和節(jié)點(diǎn)信息。znode 可以用于存儲(chǔ)數(shù)據(jù),并且有一個(gè)與之相關(guān)聯(lián)的 ACL(詳情可見 ACL)。ZooKeeper 的設(shè)計(jì)目標(biāo)是實(shí)現(xiàn)協(xié)調(diào)服務(wù),而不是真的作為一個(gè)文件存儲(chǔ),因此 znode 存儲(chǔ)數(shù)據(jù)的大小被限制在 1MB 以內(nèi)。

ZooKeeper 的數(shù)據(jù)訪問具有原子性。其讀寫操作都是要么全部成功,要么全部失敗。

znode 通過路徑被引用。znode 節(jié)點(diǎn)路徑必須是絕對(duì)路徑。

znode 有兩種類型:

  • 臨時(shí)的( EPHEMERAL ):戶端會(huì)話結(jié)束時(shí),ZooKeeper 就會(huì)刪除臨時(shí)的 znode。

  • 持久的(PERSISTENT ):除非客戶端主動(dòng)執(zhí)行刪除操作,否則 ZooKeeper 不會(huì)刪除持久的 znode。

2.2? 節(jié)點(diǎn)信息

znode 上有一個(gè)順序標(biāo)志(?SEQUENTIAL?)。如果在創(chuàng)建 znode 時(shí),設(shè)置了順序標(biāo)志(?SEQUENTIAL?),那么 ZooKeeper 會(huì)使用計(jì)數(shù)器為 znode 添加一個(gè)單調(diào)遞增的數(shù)值,即 zxid。ZooKeeper 正是利用 zxid 實(shí)現(xiàn)了嚴(yán)格的順序訪問控制能力。

每個(gè) znode 節(jié)點(diǎn)在存儲(chǔ)數(shù)據(jù)的同時(shí),都會(huì)維護(hù)一個(gè)叫做 Stat 的數(shù)據(jù)結(jié)構(gòu),里面存儲(chǔ)了關(guān)于該節(jié)點(diǎn)的全部狀態(tài)信息。如下:

2.3 集群角色

Zookeeper 集群是一個(gè)基于主從復(fù)制的高可用集群,每個(gè)服務(wù)器承擔(dān)如下三種角色中的一種。

  • Leader:它負(fù)責(zé)?發(fā)起并維護(hù)與各 Follwer 及 Observer 間的心跳。所有的寫操作必須要通過 Leader 完成再由 Leader 將寫操作廣播給其它服務(wù)器。一個(gè) Zookeeper 集群同一時(shí)間只會(huì)有一個(gè)實(shí)際工作的 Leader。

  • Follower:它會(huì)響應(yīng) Leader 的心跳。Follower 可直接處理并返回客戶端的讀請(qǐng)求,同時(shí)會(huì)將寫請(qǐng)求轉(zhuǎn)發(fā)給 Leader 處理,并且負(fù)責(zé)在 Leader 處理寫請(qǐng)求時(shí)對(duì)請(qǐng)求進(jìn)行投票。一個(gè) Zookeeper 集群可能同時(shí)存在多個(gè) Follower。

  • Observer:角色與 Follower 類似,但是無(wú)投票權(quán)。

2.4 ACL

ZooKeeper 采用 ACL(Access Control Lists)策略來(lái)進(jìn)行權(quán)限控制。

每個(gè) znode 創(chuàng)建時(shí)都會(huì)帶有一個(gè) ACL 列表,用于決定誰(shuí)可以對(duì)它執(zhí)行何種操作。

ACL 依賴于 ZooKeeper 的客戶端認(rèn)證機(jī)制。ZooKeeper 提供了以下幾種認(rèn)證方式:

  • digest:用戶名和密碼 來(lái)識(shí)別客戶端

  • sasl:通過 kerberos 來(lái)識(shí)別客戶端

  • ip:通過 IP 來(lái)識(shí)別客戶端

ZooKeeper 定義了如下五種權(quán)限:

  • CREATE:允許創(chuàng)建子節(jié)點(diǎn);

  • READ:允許從節(jié)點(diǎn)獲取數(shù)據(jù)并列出其子節(jié)點(diǎn);

  • WRITE:允許為節(jié)點(diǎn)設(shè)置數(shù)據(jù);

  • DELETE:允許刪除子節(jié)點(diǎn);

  • ADMIN:允許為節(jié)點(diǎn)設(shè)置權(quán)限。

三、ZooKeeper 工作原理

3.1 讀操作

Leader/Follower/Observer 都可直接處理讀請(qǐng)求,從本地內(nèi)存中讀取數(shù)據(jù)并返回給客戶端即可。

由于處理讀請(qǐng)求不需要服務(wù)器之間的交互,Follower/Observer 越多,整體系統(tǒng)的讀請(qǐng)求吞吐量越大,也即讀性能越好。

3.2 寫操作

所有的寫請(qǐng)求實(shí)際上都要交給 Leader 處理。Leader 將寫請(qǐng)求以事務(wù)形式發(fā)給所有 Follower 并等待 ACK,一旦收到半數(shù)以上 Follower 的 ACK,即認(rèn)為寫操作成功。

3.2.1?寫 Leader

由上圖可見,通過 Leader 進(jìn)行寫操作,主要分為五步:

  • 客戶端向 Leader 發(fā)起寫請(qǐng)求。

  • Leader 將寫請(qǐng)求以事務(wù) Proposal 的形式發(fā)給所有 Follower 并等待 ACK。

  • Follower 收到 Leader 的事務(wù) Proposal 后返回 ACK。

  • Leader 得到過半數(shù)的 ACK(Leader 對(duì)自己默認(rèn)有一個(gè) ACK)后向所有的 Follower 和 Observer 發(fā)送 Commmit。

  • Leader 將處理結(jié)果返回給客戶端。

  • 注意

    • Leader 不需要得到 Observer 的 ACK,即 Observer 無(wú)投票權(quán)。

    • Leader 不需要得到所有 Follower 的 ACK,只要收到過半的 ACK 即可,同時(shí) Leader 本身對(duì)自己有一個(gè) ACK。上圖中有 4 個(gè) Follower,只需其中兩個(gè)返回 ACK 即可,因?yàn)?$$(2+1) / (4+1) > 1/2$$ 。

    • Observer 雖然無(wú)投票權(quán),但仍須同步 Leader 的數(shù)據(jù)從而在處理讀請(qǐng)求時(shí)可以返回盡可能新的數(shù)據(jù)。

    3.2.2?寫 Follower/Observer

    Follower/Observer 均可接受寫請(qǐng)求,但不能直接處理,而需要將寫請(qǐng)求轉(zhuǎn)發(fā)給 Leader 處理。

    除了多了一步請(qǐng)求轉(zhuǎn)發(fā),其它流程與直接寫 Leader 無(wú)任何區(qū)別。

    3.3 事務(wù)

    對(duì)于來(lái)自客戶端的每個(gè)更新請(qǐng)求,ZooKeeper 具備嚴(yán)格的順序訪問控制能力。

    為了保證事務(wù)的順序一致性,ZooKeeper 采用了遞增的事務(wù) id 號(hào)(zxid)來(lái)標(biāo)識(shí)事務(wù)。

    Leader 服務(wù)會(huì)為每一個(gè) Follower 服務(wù)器分配一個(gè)單獨(dú)的隊(duì)列,然后將事務(wù) Proposal 依次放入隊(duì)列中,并根據(jù) FIFO(先進(jìn)先出) 的策略進(jìn)行消息發(fā)送。Follower 服務(wù)在接收到 Proposal 后,會(huì)將其以事務(wù)日志的形式寫入本地磁盤中,并在寫入成功后反饋給 Leader 一個(gè) Ack 響應(yīng)。當(dāng) Leader 接收到超過半數(shù) Follower 的 Ack 響應(yīng)后,就會(huì)廣播一個(gè) Commit 消息給所有的 Follower 以通知其進(jìn)行事務(wù)提交,之后 Leader 自身也會(huì)完成對(duì)事務(wù)的提交。而每一個(gè) Follower 則在接收到 Commit 消息后,完成事務(wù)的提交。

    所有的提議(proposal)都在被提出的時(shí)候加上了 zxid。zxid 是一個(gè) 64 位的數(shù)字,它的高 32 位是 epoch 用來(lái)標(biāo)識(shí) Leader 關(guān)系是否改變,每次一個(gè) Leader 被選出來(lái),它都會(huì)有一個(gè)新的 epoch,標(biāo)識(shí)當(dāng)前屬于那個(gè) leader 的統(tǒng)治時(shí)期。低 32 位用于遞增計(jì)數(shù)。

    詳細(xì)過程如下:

    • Leader 等待 Server 連接;

    • Follower 連接 Leader,將最大的 zxid 發(fā)送給 Leader;

    • Leader 根據(jù) Follower 的 zxid 確定同步點(diǎn);

    • 完成同步后通知 follower 已經(jīng)成為 uptodate 狀態(tài);

    • Follower 收到 uptodate 消息后,又可以重新接受 client 的請(qǐng)求進(jìn)行服務(wù)了。

    3.4 觀察

    客戶端注冊(cè)監(jiān)聽它關(guān)心的 znode,當(dāng) znode 狀態(tài)發(fā)生變化(數(shù)據(jù)變化、子節(jié)點(diǎn)增減變化)時(shí),ZooKeeper 服務(wù)會(huì)通知客戶端。

    客戶端和服務(wù)端保持連接一般有兩種形式:

    • 客戶端向服務(wù)端不斷輪詢

    • 服務(wù)端向客戶端推送狀態(tài)

    Zookeeper 的選擇是服務(wù)端主動(dòng)推送狀態(tài),也就是觀察機(jī)制( Watch )。

    ZooKeeper 的觀察機(jī)制允許用戶在指定節(jié)點(diǎn)上針對(duì)感興趣的事件注冊(cè)監(jiān)聽,當(dāng)事件發(fā)生時(shí),監(jiān)聽器會(huì)被觸發(fā),并將事件信息推送到客戶端。

    客戶端使用 getData 等接口獲取 znode 狀態(tài)時(shí)傳入了一個(gè)用于處理節(jié)點(diǎn)變更的回調(diào),那么服務(wù)端就會(huì)主動(dòng)向客戶端推送節(jié)點(diǎn)的變更:

    從這個(gè)方法中傳入的 Watcher 對(duì)象實(shí)現(xiàn)了相應(yīng)的 process 方法,每次對(duì)應(yīng)節(jié)點(diǎn)出現(xiàn)了狀態(tài)的改變,WatchManager 都會(huì)通過以下的方式調(diào)用傳入 Watcher 的方法:

    Set<Watcher>?triggerWatch(String?path,?EventType?type,?Set<Watcher>?supress)?{ WatchedEvent e = new WatchedEvent(type, KeeperState.SyncConnected, path); Set<Watcher> watchers; synchronized (this) { watchers = watchTable.remove(path); } for (Watcher w : watchers) { w.process(e); } return

    Zookeeper 中的所有數(shù)據(jù)其實(shí)都是由一個(gè)名為 DataTree 的數(shù)據(jù)結(jié)構(gòu)管理的,所有的讀寫數(shù)據(jù)的請(qǐng)求最終都會(huì)改變這顆樹的內(nèi)容,在發(fā)出讀請(qǐng)求時(shí)可能會(huì)傳入 Watcher 注冊(cè)一個(gè)回調(diào)函數(shù),而寫請(qǐng)求就可能會(huì)觸發(fā)相應(yīng)的回調(diào),由 WatchManager 通知客戶端數(shù)據(jù)的變化。

    通知機(jī)制的實(shí)現(xiàn)其實(shí)還是比較簡(jiǎn)單的,通過讀請(qǐng)求設(shè)置 Watcher 監(jiān)聽事件,寫請(qǐng)求在觸發(fā)事件時(shí)就能將通知發(fā)送給指定的客戶端。

    3.5 會(huì)話

    ZooKeeper 客戶端通過 TCP 長(zhǎng)連接連接到 ZooKeeper 服務(wù)集群。會(huì)話 (Session) 從第一次連接開始就已經(jīng)建立,之后通過心跳檢測(cè)機(jī)制來(lái)保持有效的會(huì)話狀態(tài)。通過這個(gè)連接,客戶端可以發(fā)送請(qǐng)求并接收響應(yīng),同時(shí)也可以接收到 Watch 事件的通知。

    每個(gè) ZooKeeper 客戶端配置中都配置了 ZooKeeper 服務(wù)器集群列表。啟動(dòng)時(shí),客戶端會(huì)遍歷列表去嘗試建立連接。如果失敗,它會(huì)嘗試連接下一個(gè)服務(wù)器,依次類推。

    一旦一臺(tái)客戶端與一臺(tái)服務(wù)器建立連接,這臺(tái)服務(wù)器會(huì)為這個(gè)客戶端創(chuàng)建一個(gè)新的會(huì)話。每個(gè)會(huì)話都會(huì)有一個(gè)超時(shí)時(shí)間,若服務(wù)器在超時(shí)時(shí)間內(nèi)沒有收到任何請(qǐng)求,則相應(yīng)會(huì)話被視為過期。一旦會(huì)話過期,就無(wú)法再重新打開,且任何與該會(huì)話相關(guān)的臨時(shí) znode 都會(huì)被刪除。

    通常來(lái)說,會(huì)話應(yīng)該長(zhǎng)期存在,而這需要由客戶端來(lái)保證。客戶端可以通過心跳方式(ping)來(lái)保持會(huì)話不過期。

    ZooKeeper 的會(huì)話具有四個(gè)屬性:

    • sessionID:會(huì)話 ID,唯一標(biāo)識(shí)一個(gè)會(huì)話,每次客戶端創(chuàng)建新的會(huì)話時(shí),Zookeeper 都會(huì)為其分配一個(gè)全局唯一的 sessionID。

    • TimeOut:會(huì)話超時(shí)時(shí)間,客戶端在構(gòu)造 Zookeeper 實(shí)例時(shí),會(huì)配置 sessionTimeout 參數(shù)用于指定會(huì)話的超時(shí)時(shí)間,Zookeeper 客戶端向服務(wù)端發(fā)送這個(gè)超時(shí)時(shí)間后,服務(wù)端會(huì)根據(jù)自己的超時(shí)時(shí)間限制最終確定會(huì)話的超時(shí)時(shí)間。

    • TickTime:下次會(huì)話超時(shí)時(shí)間點(diǎn),為了便于 Zookeeper 對(duì)會(huì)話實(shí)行”分桶策略”管理,同時(shí)為了高效低耗地實(shí)現(xiàn)會(huì)話的超時(shí)檢查與清理,Zookeeper 會(huì)為每個(gè)會(huì)話標(biāo)記一個(gè)下次會(huì)話超時(shí)時(shí)間點(diǎn),其值大致等于當(dāng)前時(shí)間加上 TimeOut。

    • isClosing:標(biāo)記一個(gè)會(huì)話是否已經(jīng)被關(guān)閉,當(dāng)服務(wù)端檢測(cè)到會(huì)話已經(jīng)超時(shí)失效時(shí),會(huì)將該會(huì)話的 isClosing 標(biāo)記為”已關(guān)閉”,這樣就能確保不再處理來(lái)自該會(huì)話的新請(qǐng)求了。

    Zookeeper 的會(huì)話管理主要是通過?SessionTracker?來(lái)負(fù)責(zé),其采用了分桶策略(將類似的會(huì)話放在同一區(qū)塊中進(jìn)行管理)進(jìn)行管理,以便 Zookeeper 對(duì)會(huì)話進(jìn)行不同區(qū)塊的隔離處理以及同一區(qū)塊的統(tǒng)一處理。

    四、ZAB 協(xié)議

    ZooKeeper 并沒有直接采用 Paxos 算法,而是采用了名為 ZAB 的一致性協(xié)議。ZAB 協(xié)議不是 Paxos 算法,只是比較類似,二者在操作上并不相同。

    ZAB 協(xié)議是 Zookeeper 專門設(shè)計(jì)的一種支持崩潰恢復(fù)的原子廣播協(xié)議。

    ZAB 協(xié)議是 ZooKeeper 的數(shù)據(jù)一致性和高可用解決方案。

    ZAB 協(xié)議定義了兩個(gè)可以無(wú)限循環(huán)的流程:

    • 選舉 Leader:用于故障恢復(fù),從而保證高可用。

    • 原子廣播:用于主從同步,從而保證數(shù)據(jù)一致性。

    4.1 選舉 Leader

    ZooKeeper 的故障恢復(fù)

    ZooKeeper 集群采用一主(稱為 Leader)多從(稱為 Follower)模式,主從節(jié)點(diǎn)通過副本機(jī)制保證數(shù)據(jù)一致。

    • 如果 Follower 節(jié)點(diǎn)掛了?- ZooKeeper 集群中的每個(gè)節(jié)點(diǎn)都會(huì)單獨(dú)在內(nèi)存中維護(hù)自身的狀態(tài),并且各節(jié)點(diǎn)之間都保持著通訊,只要集群中有半數(shù)機(jī)器能夠正常工作,那么整個(gè)集群就可以正常提供服務(wù)。

    • 如果 Leader 節(jié)點(diǎn)掛了?- 如果 Leader 節(jié)點(diǎn)掛了,系統(tǒng)就不能正常工作了。此時(shí),需要通過 ZAB 協(xié)議的選舉 Leader 機(jī)制來(lái)進(jìn)行故障恢復(fù)。

    ZAB 協(xié)議的選舉 Leader 機(jī)制簡(jiǎn)單來(lái)說,就是:基于過半選舉機(jī)制產(chǎn)生新的 Leader,之后其他機(jī)器將從新的 Leader 上同步狀態(tài),當(dāng)有過半機(jī)器完成狀態(tài)同步后,就退出選舉 Leader 模式,進(jìn)入原子廣播模式。

    4.1.1 術(shù)語(yǔ)

    myid:每個(gè) Zookeeper 服務(wù)器,都需要在數(shù)據(jù)文件夾下創(chuàng)建一個(gè)名為 myid 的文件,該文件包含整個(gè) Zookeeper 集群唯一的 ID(整數(shù))。

    zxid:類似于 RDBMS 中的事務(wù) ID,用于標(biāo)識(shí)一次更新操作的 Proposal ID。為了保證順序性,該 zkid 必須單調(diào)遞增。因此 Zookeeper 使用一個(gè) 64 位的數(shù)來(lái)表示,高 32 位是 Leader 的 epoch,從 1 開始,每次選出新的 Leader,epoch 加一。低 32 位為該 epoch 內(nèi)的序號(hào),每次 epoch 變化,都將低 32 位的序號(hào)重置。這樣保證了 zkid 的全局遞增性。

    4.1.2 服務(wù)器狀態(tài)

    • LOOKING:不確定 Leader 狀態(tài)。該狀態(tài)下的服務(wù)器認(rèn)為當(dāng)前集群中沒有 Leader,會(huì)發(fā)起 Leader 選舉。

    • FOLLOWING:跟隨者狀態(tài)。表明當(dāng)前服務(wù)器角色是 Follower,并且它知道 Leader 是誰(shuí)。

    • LEADING:領(lǐng)導(dǎo)者狀態(tài)。表明當(dāng)前服務(wù)器角色是 Leader,它會(huì)維護(hù)與 Follower 間的心跳。

    • OBSERVING:觀察者狀態(tài)。表明當(dāng)前服務(wù)器角色是 Observer,與 Folower 唯一的不同在于不參與選舉,也不參與集群寫操作時(shí)的投票。

    4.1.3 選票數(shù)據(jù)結(jié)構(gòu)

    每個(gè)服務(wù)器在進(jìn)行領(lǐng)導(dǎo)選舉時(shí),會(huì)發(fā)送如下關(guān)鍵信息:

    • logicClock:每個(gè)服務(wù)器會(huì)維護(hù)一個(gè)自增的整數(shù),名為 logicClock,它表示這是該服務(wù)器發(fā)起的第多少輪投票。

    • state:當(dāng)前服務(wù)器的狀態(tài)。

    • self_id:當(dāng)前服務(wù)器的 myid。

    • self_zxid:當(dāng)前服務(wù)器上所保存的數(shù)據(jù)的最大 zxid。

    • vote_id:被推舉的服務(wù)器的 myid。

    • vote_zxid:被推舉的服務(wù)器上所保存的數(shù)據(jù)的最大 zxid。

    4.1.4 投票流程

    (1)自增選舉輪次

    Zookeeper 規(guī)定所有有效的投票都必須在同一輪次中。每個(gè)服務(wù)器在開始新一輪投票時(shí),會(huì)先對(duì)自己維護(hù)的 logicClock 進(jìn)行自增操作。

    (2)初始化選票

    每個(gè)服務(wù)器在廣播自己的選票前,會(huì)將自己的投票箱清空。該投票箱記錄了所收到的選票。例:服務(wù)器 2 投票給服務(wù)器 3,服務(wù)器 3 投票給服務(wù)器 1,則服務(wù)器 1 的投票箱為(2, 3), (3, 1), (1, 1)。票箱中只會(huì)記錄每一投票者的最后一票,如投票者更新自己的選票,則其它服務(wù)器收到該新選票后會(huì)在自己票箱中更新該服務(wù)器的選票。

    (3)發(fā)送初始化選票

    每個(gè)服務(wù)器最開始都是通過廣播把票投給自己。

    (4)接收外部投票

    服務(wù)器會(huì)嘗試從其它服務(wù)器獲取投票,并記入自己的投票箱內(nèi)。如果無(wú)法獲取任何外部投票,則會(huì)確認(rèn)自己是否與集群中其它服務(wù)器保持著有效連接。如果是,則再次發(fā)送自己的投票;如果否,則馬上與之建立連接。

    (5)判斷選舉輪次

    收到外部投票后,首先會(huì)根據(jù)投票信息中所包含的 logicClock 來(lái)進(jìn)行不同處理:

    • 外部投票的 logicClock大于自己的 logicClock。說明該服務(wù)器的選舉輪次落后于其它服務(wù)器的選舉輪次,立即清空自己的投票箱并將自己的 logicClock 更新為收到的 logicClock,然后再對(duì)比自己之前的投票與收到的投票以確定是否需要變更自己的投票,最終再次將自己的投票廣播出去。

    • 外部投票的 logicClock小于自己的 logicClock。當(dāng)前服務(wù)器直接忽略該投票,繼續(xù)處理下一個(gè)投票。

    • 外部投票的 logickClock 與自己的相等。當(dāng)時(shí)進(jìn)行選票 PK。

    (6)選票 PK

    選票 PK 是基于(self_id, self_zxid)與(vote_id, vote_zxid)的對(duì)比:

    • 外部投票的 logicClock大于自己的 logicClock,則將自己的 logicClock 及自己的選票的 logicClock 變更為收到的 logicClock。

    • logicClock一致,則對(duì)比二者的 vote_zxid,若外部投票的 vote_zxid 比較大,則將自己的票中的 vote_zxid 與 vote_myid 更新為收到的票中的 vote_zxid 與 vote_myid 并廣播出去,另外將收到的票及自己更新后的票放入自己的票箱。如果票箱內(nèi)已存在(self_myid, self_zxid)相同的選票,則直接覆蓋。

    • 若二者vote_zxid一致,則比較二者的 vote_myid,若外部投票的 vote_myid 比較大,則將自己的票中的 vote_myid 更新為收到的票中的 vote_myid 并廣播出去,另外將收到的票及自己更新后的票放入自己的票箱。

    (7)統(tǒng)計(jì)選票

    如果已經(jīng)確定有過半服務(wù)器認(rèn)可了自己的投票(可能是更新后的投票),則終止投票。否則繼續(xù)接收其它服務(wù)器的投票。

    (8)更新服務(wù)器狀態(tài)

    投票終止后,服務(wù)器開始更新自身狀態(tài)。若過半的票投給了自己,則將自己的服務(wù)器狀態(tài)更新為 LEADING,否則將自己的狀態(tài)更新為 FOLLOWING。

    通過以上流程分析,我們不難看出:要使 Leader 獲得多數(shù) Server 的支持,則?ZooKeeper 集群節(jié)點(diǎn)數(shù)必須是奇數(shù)。且存活的節(jié)點(diǎn)數(shù)目不得少于 N + 1

    每個(gè) Server 啟動(dòng)后都會(huì)重復(fù)以上流程。在恢復(fù)模式下,如果是剛從崩潰狀態(tài)恢復(fù)的或者剛啟動(dòng)的 server 還會(huì)從磁盤快照中恢復(fù)數(shù)據(jù)和會(huì)話信息,zk 會(huì)記錄事務(wù)日志并定期進(jìn)行快照,方便在恢復(fù)時(shí)進(jìn)行狀態(tài)恢復(fù)。

    4.2 原子廣播(Atomic Broadcast)

    ZooKeeper 通過副本機(jī)制來(lái)實(shí)現(xiàn)高可用。

    那么,ZooKeeper 是如何實(shí)現(xiàn)副本機(jī)制的呢?答案是:ZAB 協(xié)議的原子廣播。

    ZAB 協(xié)議的原子廣播要求:

    所有的寫請(qǐng)求都會(huì)被轉(zhuǎn)發(fā)給 Leader,Leader 會(huì)以原子廣播的方式通知 Follow。當(dāng)半數(shù)以上的 Follow 已經(jīng)更新狀態(tài)持久化后,Leader 才會(huì)提交這個(gè)更新,然后客戶端才會(huì)收到一個(gè)更新成功的響應(yīng)。這有些類似數(shù)據(jù)庫(kù)中的兩階段提交協(xié)議。

    在整個(gè)消息的廣播過程中,Leader 服務(wù)器會(huì)每個(gè)事物請(qǐng)求生成對(duì)應(yīng)的 Proposal,并為其分配一個(gè)全局唯一的遞增的事務(wù) ID(ZXID),之后再對(duì)其進(jìn)行廣播。

    五、ZooKeeper 應(yīng)用

    ZooKeeper 可以用于發(fā)布/訂閱、負(fù)載均衡、命令服務(wù)、分布式協(xié)調(diào)/通知、集群管理、Master 選舉、分布式鎖和分布式隊(duì)列等功能?。

    5.1 命名服務(wù)

    在分布式系統(tǒng)中,通常需要一個(gè)全局唯一的名字,如生成全局唯一的訂單號(hào)等,ZooKeeper 可以通過順序節(jié)點(diǎn)的特性來(lái)生成全局唯一 ID,從而可以對(duì)分布式系統(tǒng)提供命名服務(wù)。

    5.2 配置管理

    利用 ZooKeeper 的觀察機(jī)制,可以將其作為一個(gè)高可用的配置存儲(chǔ)器,允許分布式應(yīng)用的參與者檢索和更新配置文件。

    5.3 分布式鎖

    可以通過 ZooKeeper 的臨時(shí)節(jié)點(diǎn)和 Watcher 機(jī)制來(lái)實(shí)現(xiàn)分布式鎖。

    舉例來(lái)說,有一個(gè)分布式系統(tǒng),有三個(gè)節(jié)點(diǎn) A、B、C,試圖通過 ZooKeeper 獲取分布式鎖。

    (1)訪問?/lock?(這個(gè)目錄路徑由程序自己決定),創(chuàng)建?帶序列號(hào)的臨時(shí)節(jié)點(diǎn)(EPHEMERAL)?。

    (2)每個(gè)節(jié)點(diǎn)嘗試獲取鎖時(shí),拿到?/locks節(jié)點(diǎn)下的所有子節(jié)點(diǎn)(id_0000,id_0001,id_0002),判斷自己創(chuàng)建的節(jié)點(diǎn)是不是最小的。

    • 如果是,則拿到鎖。

      釋放鎖:執(zhí)行完操作后,把創(chuàng)建的節(jié)點(diǎn)給刪掉。

    • 如果不是,則監(jiān)聽比自己要小 1 的節(jié)點(diǎn)變化。

    (3)釋放鎖,即刪除自己創(chuàng)建的節(jié)點(diǎn)。

    圖中,NodeA 刪除自己創(chuàng)建的節(jié)點(diǎn) id_0000,NodeB 監(jiān)聽到變化,發(fā)現(xiàn)自己的節(jié)點(diǎn)已經(jīng)是最小節(jié)點(diǎn),即可獲取到鎖。

    5.4 集群管理

    ZooKeeper 還能解決大多數(shù)分布式系統(tǒng)中的問題:

    • 如可以通過創(chuàng)建臨時(shí)節(jié)點(diǎn)來(lái)建立心跳檢測(cè)機(jī)制。如果分布式系統(tǒng)的某個(gè)服務(wù)節(jié)點(diǎn)宕機(jī)了,則其持有的會(huì)話會(huì)超時(shí),此時(shí)該臨時(shí)節(jié)點(diǎn)會(huì)被刪除,相應(yīng)的監(jiān)聽事件就會(huì)被觸發(fā)。

    • 分布式系統(tǒng)的每個(gè)服務(wù)節(jié)點(diǎn)還可以將自己的節(jié)點(diǎn)狀態(tài)寫入臨時(shí)節(jié)點(diǎn),從而完成狀態(tài)報(bào)告或節(jié)點(diǎn)工作進(jìn)度匯報(bào)。

    • 通過數(shù)據(jù)的訂閱和發(fā)布功能,ZooKeeper 還能對(duì)分布式系統(tǒng)進(jìn)行模塊的解耦和任務(wù)的調(diào)度。

    • 通過監(jiān)聽機(jī)制,還能對(duì)分布式系統(tǒng)的服務(wù)節(jié)點(diǎn)進(jìn)行動(dòng)態(tài)上下線,從而實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)擴(kuò)容。

    5.5 選舉 Leader 節(jié)點(diǎn)

    分布式系統(tǒng)一個(gè)重要的模式就是主從模式 (Master/Salves),ZooKeeper 可以用于該模式下的 Matser 選舉。可以讓所有服務(wù)節(jié)點(diǎn)去競(jìng)爭(zhēng)性地創(chuàng)建同一個(gè) ZNode,由于 ZooKeeper 不能有路徑相同的 ZNode,必然只有一個(gè)服務(wù)節(jié)點(diǎn)能夠創(chuàng)建成功,這樣該服務(wù)節(jié)點(diǎn)就可以成為 Master 節(jié)點(diǎn)。

    5.6?隊(duì)列管理

    ZooKeeper 可以處理兩種類型的隊(duì)列:

    • 當(dāng)一個(gè)隊(duì)列的成員都聚齊時(shí),這個(gè)隊(duì)列才可用,否則一直等待所有成員到達(dá),這種是同步隊(duì)列。

    • 隊(duì)列按照 FIFO 方式進(jìn)行入隊(duì)和出隊(duì)操作,例如實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者模型。

    同步隊(duì)列用 ZooKeeper 實(shí)現(xiàn)的實(shí)現(xiàn)思路如下:

    創(chuàng)建一個(gè)父目錄 /synchronizing,每個(gè)成員都監(jiān)控標(biāo)志(Set Watch)位目錄 /synchronizing/start 是否存在,然后每個(gè)成員都加入這個(gè)隊(duì)列,加入隊(duì)列的方式就是創(chuàng)建 /synchronizing/member_i 的臨時(shí)目錄節(jié)點(diǎn),然后每個(gè)成員獲取 / synchronizing 目錄的所有目錄節(jié)點(diǎn),也就是 member_i。判斷 i 的值是否已經(jīng)是成員的個(gè)數(shù),如果小于成員個(gè)數(shù)等待 /synchronizing/start 的出現(xiàn),如果已經(jīng)相等就創(chuàng)建 /synchronizing/start。

    總結(jié)

    以上是生活随笔為你收集整理的一文教你掌握 ZooKeeper 核心知识的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。