在zookeeper系列的前三篇,介紹分佈式數據一致性的相關原理及經典的分佈式一致性算法,比如:2PC,3PC,Paxos算法。在本篇,我們正式開始介紹Zookeeper,Zookeeper是分佈式一致性問題的工業解決方案,是常用的分佈式協調框架。本篇,會介紹Zookeeper的基本概念,數據模型,節點特性,Watcher機制及ACL等機制,在後邊我們會介紹Zookeeper爲了保證一致性使用的算法ZAB,以及Zookeeper的應用場景。
Zookeeper基本概述
從同一個客戶端發起的事務請求,最終將會嚴格按照其發起順序被應用到ZooKeeper中。
所有事務請求的結果在集羣中所有機器上的應用情況是一致的,也就是說要麼整個集羣所有集羣都成功應用了某一個事務,要麼都沒有應用,一定不會出現集羣中部分機器應用了該事務,而另外一部分沒有應用的情況。
無論客戶端連接的是哪個ZooKeeper服務器,其看到的服務端數據模型都是一致的。
一旦服務端成功地應用了一個事務,並完成對客戶端的響應,那麼該事務所引起的服務端狀態變更將會被一直保留下來,除非有另一個事務又對其進行了變更。
通常人們看到實時性的第一反應是,一旦一個事務被成功應用,那麼客戶端能夠立即從服務端上讀取到這個事務變更後的最新數據狀態。這裏需要注意的是,ZooKeeper僅僅保證在一定的時間段內,客戶端最終一定能夠從服務端上讀取到最新的數據狀態。
集羣角色
在ZooKeeper中,有三種角色:
- Leader
- Follower
- Observer
一個ZooKeeper集羣同一時刻只會有一個Leader,其他都是Follower或Observer。2181端口。
Zookeeper集羣中的任何一臺機器都可以響應客戶端的讀操作,且全量數據都存在於內存中,因此Zookeeper更適合以讀操作爲主的應用場景。注意,當不是leader的服務器收到客戶端事務操作,他會將其轉發到Leader,讓Leader進行處理。
ZooKeeper集羣的所有機器通過一個Leader選舉過程來選定一臺被稱爲『Leader』的機器,Leader服務器爲客戶端提供讀和寫服務。Follower和Observer都能提供讀服務,不能提供寫服務。兩者唯一的區別在於,Observer機器不參與Leader選舉過程,也不參與寫操作的『過半寫成功』策略,因此Observer可以在不影響寫性能的情況下提升集羣的讀性能。2 Zookeeper啓動時,將從實例中選舉一個leader(Paxos協議);
3 Leader負責處理數據更新等操作(Zab協議);
4 一個更新操作成功,當且僅當大多數Server在內存中成功修改
會話
Zookeeper數據模型
節點特性
持久節點(PERSISTENT)
所謂持久節點,是指在節點創建後,就一直存在,直到有刪除操作來主動清除這個節點——不會因爲創建該節點的客戶端會話失效而消失。
持久順序節點(PERSISTENT_SEQUENTIAL)
在ZK中,每個父節點會爲他的第一級子節點維護一份時序,會記錄每個子節點創建的先後順序。基於這個特性,在創建子節點的時候(注意:在此節點下的子節點是由順序的),可以設置這個屬性,那麼在創建節點過程中,ZK會自動爲給定節點名加上一個數字後綴,作爲新的節點名。這個數字後綴的上限是整型的最大值。
臨時節點(EPHEMERAL)
和持久節點不同的是,臨時節點的生命週期和客戶端會話綁定。也就是說,如果客戶端會話失效,那麼這個節點就會自動被清除掉。注意,這裏提到的是會話失效,而非連接斷開。另外,在臨時節點下面不能創建子節點,注意是更具Session會話的失效時間來設定的。
臨時順序節點(EPHEMERAL_SEQUENTIAL)
臨時順序節點的特性和臨時節點一致,同時是在臨時節點的基礎上,添加了順序的特性。
ZooKeeper中每個znode的Stat結構體由下述字段構成:
- czxid:創建節點的事務的zxid
- mzxid:對znode最近修改的zxid
- ctime:以距離時間原點(epoch)的毫秒數表示的znode創建時間
- mtime:以距離時間原點(epoch)的毫秒數表示的znode最近修改時間
- version:znode數據的修改次數
- cversion:znode子節點修改次數
- aversion:znode的ACL修改次數
- ephemeralOwner:如果znode是臨時節點,則指示節點所有者的會話ID;如果不是臨時節點,則爲零。
- dataLength:znode數據長度。
- numChildren:znode子節點個數。
版本--保證分佈式數據原子操作
- version:znode數據的修改次數
- cversion:znode子節點修改次數
- aversion:znode的ACL修改次數
在介紹version時,我們可以簡單的瞭解在數據庫技術中,通常提到的“悲觀鎖”和“樂觀鎖”:
悲觀鎖:具有嚴格的獨佔和排他特性,能偶有效的避免不同事務在同一數據併發更新而造成的數據一致性問題。實現原理就是:假設A事務正在對數據進行處理,那麼在整個處理過程中,都會將數據處於鎖定的狀態,在這期間,其他事務將無法對這個數據進行更新操作,直到事務A完成對該數據的處理,釋放對應的鎖。一份數據只會分配一把鑰匙,如數據庫的表鎖或者行鎖(for update).
樂觀鎖:具體實現是,表中有一個版本字段,第一次讀的時候,獲取到這個字段。處理完業務邏輯開始更新的時候,需要再次查看該字段的值是否和第一次的一樣。如果一樣更新,反之拒絕。樂觀鎖就是假定多個事務在處理過程中不會影響彼此,悲觀鎖正好相反,因此樂觀鎖在事務處理的絕大部分時間裏不需要進行加鎖處理。樂觀鎖非常適用於在數據競爭不大,事務衝突較少的應用場景中。最經典的應用就是:JDK中的CAS處理。
Zookeeper的版本作用就是類似於樂觀鎖機制,用於實現樂觀鎖機制的“寫入校驗”.
Watcher機制
1.一次性觸發 數據發生改變時,一個watcher event會被髮送到client,但是client只會收到一次這樣的信息。
2.watcher event異步發送 watcher 的通知事件從server發送到client是異步的,這就存在一個問題,不同的客戶端和服務器之間通過socket進行通信,由於網絡延遲或其他因素導致客戶端在不通的時刻監聽到事件,由於Zookeeper本身提供了ordering guarantee,即客戶端監聽事件後,纔會感知它所監視znode發生了變化。
3.數據監視 Zookeeper有數據監視和子數據監視 getdata() and exists() 設置數據監視,getchildren()設置了子節點監視
其監聽的事件有:
NodeDataChanged事件:此處的變更包括數據節點內容和數據的版本號DateVersion。因此,對於Zookeeper來說,無論數據內容是否更改,還是會觸發這個事件的通知,一旦客戶端調用了數據更新接口,且更新成功,就會更新dataversion值。
ACL--保障數據的安全
username:BASE64(SHA1(password))
,scheme爲ip時,id的值爲客戶端的ip地址。scheme爲world時,id的值爲anyone
。scheme
digest:username:BASE64(SHA1(password)):cdrwa
digest:是授權方式
username:BASE64(SHA1(password)):是id部分
cdrwa:權限部份
## 創建節點/node_05
shell> create /node_05 data
Created /node_05
## 設置權限
shell> setAcl /node_05 digest:yangxin:ACFm5rWnnKn9K9RN/Oc8qEYGYDs=:cdrwa
cZxid = 0x8e
ctime = Mon Nov 14 21:38:52 CST 2016
mZxid = 0x8e
mtime = Mon Nov 14 21:38:52 CST 2016
pZxid = 0x8e
cversion = 0
dataVersion = 0
aclVersion = 1
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
## 獲取節點剛剛設置的權限
shell> getAcl /node_05
'digest,'yangxin:ACFm5rWnnKn9K9RN/Oc8qEYGYDs=
: cdrwa
## 沒有授權,創建節點失敗
shell> create /node_05/node_05_01 data
Authentication is not valid : /node_05/node_05_01
## 添加授權信息
shell> addauth digest yangxin:123456
## 添加授權信息後,就可以正常操作了
shell> create /node_05/node_05_01 data
Created /node_05/node_05_01
2. IP比如,設置某個節點只允許IP爲
192.168.1.100
的客戶端能讀寫該寫節點的數據:ip:192.168.1.100:rw
world:anyone:cdrwa
創建節點默認的scheme,所有人都可以訪問。如下所示:
permission
digest:username:BASE64(SHA1(password)):cdrwa
中的cdrwa即是permission。 1> CREATE(r):創建子節點的權限
2> DELETE(d):刪除節點的權限
3> READ(r):讀取節點數據的權限
4> WRITE(w):修改節點數據的權限
5> ADMIN(a):設置子節點權限的權限
Zookeeper內存模型
Zookeeper的數據模型是樹結構,在內存數據庫中,存儲了整棵樹的內容,包括所有的節點路徑、節點數據、ACL信息,Zookeeper會定時將這個數據存儲到磁盤上。
1. DataTree
DataTree是內存數據存儲的核心,是一個樹結構,代表了內存中一份完整的數據。DataTree不包含任何與網絡、客戶端連接及請求處理相關的業務邏輯,是一個獨立的組件。
2. DataNode
DataNode是數據存儲的最小單元,其內部除了保存了結點的數據內容、ACL列表、節點狀態之外,還記錄了父節點的引用和子節點列表兩個屬性,其也提供了對子節點列表進行操作的接口。
3. ZKDatabase
Zookeeper的內存數據庫,管理Zookeeper的所有會話、DataTree存儲和事務日誌。ZKDatabase會定時向磁盤dump快照數據,同時在Zookeeper啓動時,會通過磁盤的事務日誌和快照文件恢復成一個完整的內存數據庫。