天天看點

你真的了解zookeeper嗎?

一、什麼是zookeeper

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

ZooKeeper的目标就是封裝好複雜易出錯的關鍵服務,将簡單易用的接口和性能高效、功能穩定的系統提供給使用者。

ZooKeeper包含一個簡單的原語集,提供Java和C的接口。

ZooKeeper代碼版本中,提供了分布式獨享鎖、選舉、隊列的接口,代碼在$zookeeper_home\src\recipes。其中分布鎖和隊列有Java和C兩個版本,選舉隻有Java版本。

它是一個為分布式應用提供一緻性服務的軟體,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。

ZooKeeper 的目标就是封裝好複雜易出錯的關鍵服務,将簡單易用的接口和性能高效、功能穩定的系統提供給使用者。

Zookeeper 保證了如下分布式一緻性特性:

(1)順序一緻性

(2)原子性

(3)單一視圖

(4)可靠性

(5)實時性(最終一緻性)

二、基本運轉流程

ZooKeeper的基本運轉流程:

  1. 選舉Leader。
  2. 同步資料。
  3. 選舉Leader過程中算法有很多,但要達到的選舉标準是一緻的。
  4. Leader要具有最高的執行ID,類似root權限。
  5. 叢集中大多數的機器得到響應并接受選出的Leader。

三、提供了什麼

(1)檔案系統

Zookeeper 提供一個多層級的節點命名空間(節點稱為 znode)。與檔案系統不同的是,這些節點都可以設定關聯的資料,而檔案系統中隻有檔案節點可以存放資料而目錄節點不行。Zookeeper 為了保證高吞吐和低延遲,在記憶體中維護了這個樹狀的目錄結構,這種特性使得 Zookeeper 不能用于存放大量的資料,每個節點的存放資料上限為1M。

(2)通知機制

四、ZAB協定

ZAB 協定是為分布式協調服務 Zookeeper 專門設計的一種支援崩潰恢複的原子廣播協定。ZAB 協定包括兩種基本的模式:崩潰恢複和消息廣播。當整個 zookeeper 叢集剛剛啟動或者 Leader 伺服器當機、重新開機或者網絡故障導緻不存在過半的伺服器與 Leader 伺服器保持正常通信時,所有程序(伺服器)進入崩潰恢複模式,首先選舉産生新的 Leader 伺服器,然後叢集中 Follower 伺服器開始與新的 Leader 伺服器進行資料同步,當叢集中超過半數機器與該 Leader伺服器完成資料同步之後,退出恢複模式進入消息廣播模式,Leader 伺服器開始接收用戶端的事務請求生成事物提案來進行事務請求處理。

五、四種類型的資料節點 Znode

  1. PERSISTENT-持久節點除非手動删除,否則節點一直存在于 Zookeeper 上。
  2. EPHEMERAL-臨時節點臨時節點的生命周期與用戶端會話綁定,一旦用戶端會話失效(用戶端與zookeeper 連接配接斷開不一定會話失效),那麼這個用戶端建立的所有臨時節點都會被移除。
  3. PERSISTENT_SEQUENTIAL-持久順序節點基本特性同持久節點,隻是增加了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。
  4. EPHEMERAL_SEQUENTIAL-臨時順序節點基本特性同臨時節點,增加了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。

六、Zookeeper Watcher 機制 -- 資料變更通知

Zookeeper 允許用戶端向服務端的某個 Znode 注冊一個 Watcher 監聽,當服務端的一些指定事件觸發了這個 Watcher,服務端會向指定用戶端發送一個事件通知來實作分布式的通知功能,然後用戶端根據 Watcher 通知狀态和事件類型做出業務上的改變。

工作機制:

(1)用戶端注冊 watcher

(2)服務端處理 watcher

(3)用戶端回調 watcherWatcher

特性總結:

(1)一次性無論是服務端還是用戶端,一旦一個 Watcher 被 觸 發 ,Zookeeper 都會将其從相應的存儲中移除。這樣的設計有效的減輕了服務端的壓力,不然對于更新非常頻繁的節點,服務端會不斷的向用戶端發送事件通知,無論對于網絡還是服務端的壓力都非常大。

(2)用戶端串行執行用戶端 Watcher 回調的過程是一個串行同步的過程。

(3)輕量3.1、Watcher 通知非常簡單,隻會告訴用戶端發生了事件,而不會說明事件的具體内容。3.2、用戶端向服務端注冊 Watcher 的時候,并不會把用戶端真實的 Watcher 對象實體傳遞到服務端,僅僅是在用戶端請求中使用 boolean 類型屬性進行了标記。

(4)watcher event 異步發送 watcher 的通知事件從 server 發送到 client 是異步的,這就存在一個問題,不同的用戶端和伺服器之間通過 socket 進行通信,由于網絡延遲或其他因素導緻用戶端在不通的時刻監聽到事件,由于 Zookeeper 本身提供了 ordering guarantee,即用戶端監聽事件後,才會感覺它所監視 znode發生了變化。是以我們使用 Zookeeper 不能期望能夠監控到節點每次的變化。Zookeeper 隻能保證最終的一緻性,而無法保證強一緻性。

(5)注冊 watcher getData、exists、getChildren

(6)觸發 watcher create、delete、setData

(7)當一個用戶端連接配接到一個新的伺服器上時,watch 将會被以任意會話事件觸發。當與一個伺服器失去連接配接的時候,是無法接收到 watch 的。而當 client 重新連接配接時,如果需要的話,所有先前注冊過的 watch,都會被重新注冊。通常這是完全透明的。隻有在一個特殊情況下,watch 可能會丢失:對于一個未建立的 znode的 exist watch,如果在用戶端斷開連接配接期間被建立了,并且随後在用戶端連接配接上之前又删除了,這種情況下,這個 watch 事件可能會被丢失。

你真的了解zookeeper嗎?

七、用戶端注冊 Watcher 實作

  1. 調用 getData()/getChildren()/exist()三個 API,傳入 Watcher 對象2.
  2. 标記請求 request,封裝 Watcher 到 WatchRegistration
  3. 封裝成 Packet 對象,發服務端發送 request
  4. 收到服務端響應後,将 Watcher 注冊到 ZKWatcherManager 中進行管理
  5. 請求傳回,完成注冊。
  6. 你真的了解zookeeper嗎?

八、服務端處理 Watcher 實作

(1)服務端接收 Watcher 并存儲接收到用戶端請求,處理請求判斷是否需要注冊 Watcher,需要的話将資料節點的節點路徑和 ServerCnxn(ServerCnxn 代表一個用戶端和服務端的連接配接,實作了 Watcher 的 process 接口,此時可以看成一個 Watcher 對象)存儲在WatcherManager 的 WatchTable 和 watch2Paths 中去。

(2)Watcher 觸發以服務端接收到 setData() 事務請求觸發 NodeDataChanged 事件為例:2.1 封裝 WatchedEvent将通知狀态(SyncConnected)、事件類型(NodeDataChanged)以及節點路徑封裝成一個 WatchedEvent 對象2.2 查詢 Watcher從 WatchTable 中根據節點路徑查找 Watcher2.3 沒找到;說明沒有用戶端在該資料節點上注冊過 Watcher2.4 找到;提取并從 WatchTable 和 Watch2Paths 中删除對應 Watcher(從這裡可以看出 Watcher 在服務端是一次性的,觸發一次就失效了)

(3)調用 process 方法來觸發 Watcher這裡 process 主要就是通過 ServerCnxn 對應的 TCP 連接配接發送 Watcher 事件通知。

你真的了解zookeeper嗎?

九、用戶端回調 Watcher

用戶端 SendThread 線程接收事件通知,交由 EventThread 線程回調 Watcher。

用戶端的 Watcher 機制同樣是一次性的,一旦被觸發後,該 Watcher 就失效了。

你真的了解zookeeper嗎?

十、ACL 權限控制機制

UGO(User/Group/Others)目前在 Linux/Unix 檔案系統中使用,也是使用最廣泛的權限控制方式。是一種粗粒度的檔案系統權限控制模式。ACL(Access Control List)通路控制清單包括三個方面:權限模式(Scheme)

(1)IP:從 IP 位址粒度進行權限控制

(2)Digest:最常用,用類似于 username:password 的權限辨別來進行權限配置,便于區分不同應用來進行權限控制

(3)World:最開放的權限控制方式,是一種特殊的 digest 模式,隻有一個權限辨別“world:anyone”

(4)Super:超級使用者授權對象授權對象指的是權限賦予的使用者或一個指定實體,例如 IP 位址或是機器燈。

權限 Permission

(1)CREATE:資料節點建立權限,允許授權對象在該 Znode 下建立子節點

(2)DELETE:子節點删除權限,允許授權對象删除該資料節點的子節點

(3)READ:資料節點的讀取權限,允許授權對象通路該資料節點并讀取其資料内容或子節點清單等

(4)WRITE:資料節點更新權限,允許授權對象對該資料節點進行更新操作

(5)ADMIN:資料節點管理權限,允許授權對象對該資料節點進行 ACL 相關設定操作

十一、會話管理

分桶政策:将類似的會話放在同一區塊中進行管理,以便于 Zookeeper 對會話進行不同區塊的隔離處理以及同一區塊的統一處理。配置設定原則:每個會話的“下次逾時時間點”(ExpirationTime)計算公式:

ExpirationTime_ = currentTime + sessionTimeoutExpirationTime = (ExpirationTime_ / ExpirationInrerval + 1) *ExpirationInterval , ExpirationInterval 是指 Zookeeper 會話逾時檢查時間間隔,預設 tickTime

十二、伺服器角色

Leader

(1)事務請求的唯一排程和處理者,保證叢集事務處理的順序性

(2)叢集内部各服務的排程者

Follower

(1)處理用戶端的非事務請求,轉發事務請求給 Leader 伺服器

(2)參與事務請求 Proposal 的投票

(3)參與 Leader 選舉投票

Observer

(1)3.0 版本以後引入的一個伺服器角色,在不影響叢集事務處理能力的基礎上提升叢集的非事務處理能力

(2)處理用戶端的非事務請求,轉發事務請求給 Leader 伺服器

(3)不參與任何形式的投票

十三、Zookeeper 下 Server 工作狀态

伺服器具有四種狀态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。

(1)LOOKING:尋 找 Leader 狀态。當伺服器處于該狀态時,它會認為目前叢集中沒有 Leader,是以需要進入 Leader 選舉狀态。

(2)FOLLOWING:跟随者狀态。表明目前伺服器角色是 Follower。

(3)LEADING:上司者狀态。表明目前伺服器角色是 Leader。

(4)OBSERVING:觀察者狀态。表明目前伺服器角色是 Observer。

十四、zookeeper 是如何保證事務的順序一緻性的?

zookeeper 采用了全局遞增的事務 Id 來辨別,所有的 proposal(提議)都在被提出的時候加上了 zxid,zxid 實際上是一個 64 位的數字,高 32 位是 epoch( 時期; 紀元; 世; 新時代)用來辨別 leader 周期,如果有新的 leader 産生出來,epoch會自增,低 32 位用來遞增計數。當新産生 proposal 的時候,會依據資料庫的兩階段過程,首先會向其他的 server 發出事務執行請求,如果超過半數的機器都能執行并且能夠成功,那麼就會開始執行。

十五、zk 節點當機如何處理?

Zookeeper 本身也是叢集,推薦配置不少于 3 個伺服器。Zookeeper 自身也要保證當一個節點當機時,其他節點會繼續提供服務。如果是一個 Follower 當機,還有 2 台伺服器提供通路,因為 Zookeeper 上的資料是有多個副本的,資料并不會丢失;如果是一個 Leader 當機,Zookeeper 會選舉出新的 Leader。ZK 叢集的機制是隻要超過半數的節點正常,叢集就能正常提供服務。隻有在 ZK節點挂得太多,隻剩一半或不到一半節點能工作,叢集才失效。

是以3 個節點的 cluster 可以挂掉 1 個節點(leader 可以得到 2 票>1.5)2 個節點的 cluster 就不能挂掉任何 1 個節點了(leader 可以得到 1 票<=1)

十六、zookeeper 負載均衡和 nginx 負載均衡差別

zk 的負載均衡是可以調控,nginx 隻是能調權重,其他需要可控的都需要自己寫插件;但是 nginx 的吞吐量比 zk 大很多,應該說按業務選擇用哪種方式。

十七、叢集支援動态添加機器嗎?

其實就是水準擴容了,Zookeeper 在這方面不太好。

兩種方式:全部重新開機:關閉所有 Zookeeper 服務,修改配置之後啟動。不影響之前用戶端的會話。

逐個重新開機:在過半存活即可用的原則下,一台機器重新開機不影響整個叢集對外提供服務。這是比較常用的方式。

3.5 版本開始支援動态擴容。

十八、Zookeeper 對節點的 watch 監聽通知是永久的嗎?為什麼不是永久的?

不是。官方聲明:一個 Watch 事件是一個一次性的觸發器,當被設定了 Watch的資料發生了改變的時候,則伺服器将這個改變發送給設定了 Watch 的用戶端,以便通知它們。

為什麼不是永久的,舉個例子,如果服務端變動頻繁,而監聽的用戶端很多情況下,每次變動都要通知到所有的用戶端,給網絡和伺服器造成很大壓力。

一般是用戶端執行 getData(“/節點 A”,true),如果節點 A 發生了變更或删除,用戶端會得到它的 watch 事件,但是在之後節點 A 又發生了變更,而用戶端又沒有設定 watch 事件,就不再給用戶端發送。

在實際應用中,很多情況下,我們的用戶端不需要知道服務端的每一次變動,我隻要最新的資料即可。

十九、ZAB 和 Paxos 算法的聯系與差別?

相同點:

(1)兩者都存在一個類似于 Leader 程序的角色,由其負責協調多個 Follower 程序的運作

(2)Leader 程序都會等待超過半數的 Follower 做出正确的回報後,才會将一個提案進行送出

(3)ZAB 協定中,每個 Proposal 中都包含一個 epoch 值來代表目前的 Leader周期,

Paxos 中名字為 Ballot不同點:ZAB 用來建構高可用的分布式資料主備系統(Zookeeper),Paxos 是用來建構分布式一緻性狀态機系統。

你真的了解zookeeper嗎?

二十、Zookeeper 的典型應用場景

Zookeeper 是一個典型的釋出/訂閱模式的分布式資料管理與協調架構,開發人員可以使用它來進行分布式資料的釋出和訂閱。

通過對 Zookeeper 中豐富的資料節點進行交叉使用,配合 Watcher 事件通知機制,可以非常友善的建構一系列分布式應用中年都會涉及的核心功能,如:

(1)資料釋出/訂閱

(2)負載均衡

(3)命名服務

(4)分布式協調/通知

(5)叢集管理

(6)Master 選舉

(7)分布式鎖

(8)分布式隊列

二十一、用戶端

HP

注:以下代碼依賴于PHP擴充libzookeeper 。

連接配接叢集:

<?php
$zc = new ZookeeperClient();
$zc->connect('192.168.0.2:2181, 192.168.0.3:2181');
?>      

建立節點:

<?php
$zc = new ZookeeperClient();
$zc->connect('localhost:2181');
$zc->create('/new_node', 'node_value');
?>      

删除節點:

<?php
$zc = new ZookeeperClient();
$zc->connect('localhost:2181');
$zc->delete('/existing_node');
?>      

擷取節點值:

<?php
$zc = new ZookeeperClient();
$zc->connect('localhost:2181');
var_dump($zc->get('/existing_node'));
?>      
<?php
$zc = new ZookeeperClient();
$zc->connect('localhost:9010');
$childNodes = $zc->getChildren('/parent_node');
foreach ($childNodes as $nodeName) {
var_dump($nodeName);
}
?>      

繼續閱讀