iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 21
0

前言

Chubby作為一個在Google內部各種分散式系統很核心的服務,可惜的是並沒有開源。因此Zookeeper的出現給大家一個更具體的想像這個服務怎麼運作與使用。

Zookeeper

Zookeeper API

  • create - 在文件系統上面創建一個node (文件系統是tree-like)
    • nodes為sequential的,也就是可以創建一系列的nodes,一個獨立且嚴格遞增的數字也是其名字的一部分。
    • E.g. node-1, node-2, node-3...
  • delete - 刪除文件系統上的一個node
  • exists - 測試該node是否存在
  • getData - 讀取指定的node上面的data
  • setData - 寫入data到指定的node
  • getChildren - 取的指定的node其所有child nodes
  • sync - 在ZAB中,Client並不像Chubby一樣只能對Leader讀寫資料,因此有可能Client連接著的replica server還沒同步到最新的值,這個指令可以要求等待值的更新同步
  • watches: 對指定的node訂閱通知,當node有更新時會收到事件。

與Chubby比較

因為參考了Chubby的設計,提供的功能也幾乎一樣

  • 提供Lock Service
  • 一樣提供類似UNIX的文件系統
  • 提供事件通知機制Event與Watcher訂閱機制
  • Node 有 Ephemeral mode 與 Client lifecycle綁定,可以作為服務發現與其他應用之用
  • 本身也是分散式系統
  • 內部利用ZAB維護replica servers的一致性
  • 利用ZAB(類似Raft)選Master

但時仍然有很多細部的地方不一樣。

Lock Service 實作

在Chubby中,每一個Node提供了Acquire()Release()的API提供Client加鎖解鎖。

但是Zookeeper的znode並沒有這樣的API,
相反的使用者必須利用基本的API來實作Lock Service

舉例: 假設有一組processes想要搶一個Lock

實作 Lock Service

1. 每一個processes都嘗試創建ephemeral sequential nodes "/data/lock-"
2. 每一個 lock-X 只會創建一次,由ZooKeeper來處理哪一個process創建了哪一個 lock-X (收到請求的時間差)
3. 每一個 process 同時 getChildren 取的 /data 底下所有的 child nodes 並起對 /data znode 設定監聽 watch
4. 規定哪一個 process 有最小的 lock-X 之 X,取得Lock
5. 當他釋放Lock時,就刪除自己的那個e phemeral sequential nodes
6. 其他的processes就會收到事件,這時在看誰是最小就代表拿到Lock -> 回到 3

以上就是最簡單利用Zookeeper實作Lock的方式。
使用到create()、getChildren()、setWatch()即可實作

改進

上述的實作效能很差,因為當process釋放Lock時,Zookeeper必須通知所有的processes。

一種修改的方式就是在第三步
對於processX創建node-X,只setWatch()在node-(X-1)前一個node上。

這樣Zookeeper只要每一次通知下一個process即可。

Cache

前面提到Chubby在Caching的部分下了很多苦心

  • 設計在Chubby library裡,利用每一次的寫更新強制invalidate Client 的Cache來達到Consistenct Caching。

Zookeeper 則是完全沒有設計Cache機制,
提供基礎的API,將這一塊保留給使用者自己開發屬於自己的Cache。

一致性

在Chubby裡面是用

  1. Paxos機制
  2. Strong Consistency
  3. 搭配單一Leader讀寫,每一次讀也會是最新的

正因為每一次讀寫都是從Leader讀,因此不管是讀或是寫都是最高等級的一致性
再藉由Paxos同步更新到其他的replica server

在Zookeeper裡面

  1. ZAB (Atomic Broadcast)
  2. Leader接受寫更新時保證total order,並且用類似Raftㄧ樣的方法同步到replica server
  3. 但是Zookeeper允許Client讀replica server的資料,因此可能還沒收到commit指令(Raft的commit)
  4. 可以利用API sync()來先等replica server收到Leader的commit訊息,再進行下一步動作。

2PC 實作

搭配Zookeeper的這些API,也可以讓你在自己的分散式系統服務中實作出2PC協定喔~

複習一下2PC

方法:

1. 先用Zookeeper實作出Leader Election,選出coordinator
2. coordinator 創建兩個znode
	1. /2PC/transaction/ 和 /2PC/transaction/result
	2. setWatch() on /2PC/transaction/

3. 其餘的 participants 則是 setWatch() on /2PC/ and /2PC/transaction/result 兩個znode

4. participants接著在 /2PC/transaction/ 底下創建 ephemeral nodes 並且在自己的 file 寫入 commit/abort 訊息

6. 因為znode /2PC/transaction/ 底下有被更新,所以 coordinator 也會收到事件通知

7. coordinator 接著讀取 participants 創建的 znode 裡面是 commit 還是 abort,並作出統計。

8. coordinator 根據 2PC 協定在/2PC/transaction/result 寫下結果是 rollback 還是 commit

9. participants 也會收到事件通知,此時讀取 /2PC/transaction/result 執行操作後,刪除自己的 ephemeral nodes

小結

今天簡介了Zookeeper與Chubby的差異,並且介紹了如何用Zookeeper實作Lock。
大家可以看到其實創建node這件事情搭配事件通知,
就成了一種分散式系統裡面的通訊方式,
進而實作更複雜的邏輯,甚至是2PC協定。

今天留了一個伏筆,那就是Zookeeper最常見的功能 "Leader Election"

明天將會介紹如何實作,不過聰明的你看完上面兩個例子,
應該可以先想一下,如果是你你會怎麼實作,
其實跟Lock Service實作方式差不多喔~


上一篇
Day 20 - Google Distributed Lock Service - Chubby(下)
下一篇
Day 22 - Zookeeper - Leader Election 與 Reverse Proxy 實作,使用Golang
系列文
分散式系統 - 在分散的世界中保持一致30

尚未有邦友留言

立即登入留言