Zookeeper基礎概念及相關原理

Algoric發表於2019-03-05

分散式協調服務

一、Zookeeper使用場景

適合讀多寫少的場景

  1. 統一命名服務

  2. 統一配置管理

  3. 分散式叢集管理(註冊中心)

  4. 分散式鎖

  5. 負載均衡

二、 Zookeeper內部結構

zookeeper節點
類似於Unix檔案系統

Zookeeper基礎概念及相關原理

每個子目錄項(路徑) 都被稱作為znode,和檔案系統一樣,我們能夠自由的增加、刪除znode,在一個znode下增加、刪除子znode,唯一的不同在於znode是可以儲存資料的。

ZooKeeper資料模型中的每個znode都維護著一個stat結構,提供後設資料,它由版本號,操作控制列表(ACL),時間戳和資料長度組成。

  • 版本號 每當與znode相關聯的資料發生變化時,其對應的版本號也會增加

  • 操作控制列表(ACL) ACL基本上是訪問znode的認證機制。它管理所有znode讀取和寫入操作

  • 時間戳 時間戳表示建立和修改znode所經過的時間,ZooKeeper從“事務ID"(zxid)標識znode的每個更改

  • 資料長度 最多儲存1M資料

節點型別

  • 持久化有序
  • 持久化無序
  • 臨時有序節點
  • 臨時無序節點

三、Zookeeper提供的原語服務

  • create /path data:建立一個名為/path的znode節點,幷包含data資料(不包含建立失敗)
  • delete /path:刪除名為/path的znode
  • exists /path:檢查是否存在名為/path的節點
  • setData /path data:設定名為/path的znode的資料為data
  • getData /path:返回名為/path節點的資料
  • getChildren /path:返回/path節點的子節點列表

四、Zookeeper分散式鎖

Zookeeper基礎概念及相關原理
思路:

  1. 客戶端client_1嘗試獲取鎖,呼叫create()方法在locker節點下建立臨時順序節點node_1
  2. 客戶端呼叫getChildren("/locker")來獲取locker節點下所有位元組點,同時在這個節點上註冊上子節點變更通知的Watcher
  3. 如果發現自己在步驟1中建立的節點是所有節點中序號最小的,那麼就認為這個客戶端獲得了鎖
  4. 在步驟3中發現自己並非是所有子節點中最小的,說明自己還沒有獲取到鎖,就開始等待,直到下次子節點變更通知的時候,再進行子節點的獲取,判斷是否獲取鎖
  5. 釋放鎖就是刪除自己建立的那個子節點即可

上面的過程有問題:
首先在分散式鎖中,會有很多客戶端來嘗試獲取鎖,他們在判斷自己節點獲取的結果都是自己不是最小節點,在最小節點被刪除時,客戶端會受到大量無效通知——羊群效應
我們的關注點是:每個節點只關注比自己序號小的那個節點的狀態。

改進分散式鎖:

  1. 客戶端client_1嘗試獲取鎖,呼叫create()方法在locker節點下建立臨時順序節點node_1

  2. 客戶端呼叫getChildren("/locker")來獲取locker節點下所有位元組點,這裡向比它靠前節點註冊Watcher;

  3. 如果發現自己在步驟1中建立的節點是所有節點中序號最小的,那麼就認為這個客戶端獲得了鎖

  4. 在步驟3中發現自己並非是所有子節點中最小的,說明自己還沒有獲取到鎖,就開始等待,直到下次子節點變更通知的時候,再進行子節點的獲取,判斷是否獲取鎖

  5. 最終會形成Client_1得到了鎖,Client_2監聽了node1,Client_3監聽了node2,形成一個等待佇列,有點類似AQS

  6. 釋放鎖就是刪除自己建立的那個子節點即可,並且只有相鄰節點會收到通知,判斷自己是不是最小,獲取鎖。

Zookeeper作為分散式鎖非常容易實現,但是增刪節點效率偏低。

五、Zookeeper分散式叢集

1. Zookeeper的角色:

Zookeeper基礎概念及相關原理

  • 領導者(Leader),負責進行投票的發起和決議,更新系統狀態
  • 學習者(Learner),包括跟隨者(Follower)和觀察者(observer):
    Follower用於接受客戶端請求並想客戶端返回結果,在選主過程中參與投票,Observer可以接受客戶端連線,將寫請求轉發給Leader,但observer不參加投票過程,只同步Leader的狀態,observer的目的是為了擴充套件系統,提高讀取速度

2. Zookeeper下Server的工作狀態

Looking :選舉狀態
Following :Leader已經選舉產生,當前Server與之同步
Leading :主節點所處的狀態

3. Zookeeper工作原理

Zookeeper核心:原子廣播,通過Zab協議實現
ZAB協議兩種模式:訊息廣播和崩潰恢復

Zookeeper基礎概念及相關原理

訊息廣播:

  1. 在Client向Follwer發出一個寫的請求

  2. Follwer把請求傳送轉發給Leader

  3. Leader接收到以後開始發起投票並通知Follwer進行投票, 注:Observer不參與

  4. Follwer把投票結果傳送給Leader

  5. Leader將結果彙總,廣播通知所有Follower寫入資料,

  6. Follower寫入完成後,同時把寫入操作通過ACK訊息通知給Leader,Leader收到半數以上成功ACK(這裡會造成Zookeeper讀資料的時候,資料不一致,半數以上為新資料,半數以下存在老資料,所以在讀資料是需要呼叫sync()同步方法),進行commit,並進行廣播;
    注:對於zookeeper來說,它實現了A可用性、P分割槽容錯性、C中的寫入強一致性,喪失的是C中的讀取一致性

  7. Follwer把請求結果返回給Client

Zookeeper為保持事務的順序性,採用遞增的zxid標識每個每個提議,zxid是64位數字,高32位epoch標識Leader狀態,就是Leader統治狀態,每次選出新的Leader同時就會產生新的epoch,低32位用來自增。

Zookeeper選主過程:

Zookeeper第一次進行選主過程:

Zookeeper叢集有5個Server
投票過程:server1連入Zookeeper,投票給自己,成為Leader,Server2連入,投票給自己和Server1,發現Server2的zxid較新,Server2當選成為新Leader
Server3連入,重複上面過程,成為Leader,這時有超過半數以上Server投票給Server3,Server3當選成為Leader,Server4,5連入,就算zxid最新,也不會當選成為Leader。

崩潰恢復:
這個過程很複雜,以下是個人理解: Zookeeper選舉演算法有兩種模式:

  • Basic Paxos
  • Fast Paxos
    預設使用Fast Paxos.

選舉過程:

  1. 選舉執行緒由當前Server發起選舉的執行緒擔任,主要功能是對投票結果進行統計,並選出推薦的Server

  2. 選舉階段,所有叢集的節點處於Looking狀態,它們會向其它節點發起投票,投票內容包含(伺服器ID, zxid).

  3. 該節點同時會收到其它節點的投票,它會將自身zxid和其它zxid比較,選擇最新的zxid,重新發起投票.

  4. 發起選舉的執行緒統計票數,判斷過半獲得投票的節點,並將它設定為Leader,狀態變為Leading,其它節點狀態變為Following

  5. 這個時候,如果上一個Leader並不是掛掉,而是因為網路問題,通訊延遲,現在恢復通訊,就會因為兩個Leader產生腦裂情況.
    所以進入發現階段:
    Leader會收集所有Follwer的Zxid,Leader會選出最大Zxid,基於zxid的epoch加1,,再將這個生成的zxid廣播給所有的Follower,各個Follower收到全新的zxid後,返回ACK給Leader,帶上各自最大的zxid和歷史事務日誌,Leader選出最大的zxid,並更新自身歷史日誌,這種情況就可以避免腦裂

  6. Leader將最新的事務日誌,同步給所有Follower,當半數Follower同步成功,這個Leader就開始了自己的統治時代

相關文章