一、數據模型
ZooKeeper的視圖結構和標準的Unix文件系統非常類似,但沒有引入傳統文件系統中目錄和文件等相關概念,而是使用了其特有的“數據節點”概念,我們稱之爲ZNode.ZNode是ZooKeeper中數據的最小單元,每個ZNode上都可以保存數據,同時還可以掛載子節點,因此構成了一個層次化的命名空間,我們稱之爲樹。
1.1 樹
ZooKeeper中,每- -個數據節點都被稱爲-一個ZNode,所有ZNode按層次化結構進行組織,形成- - 棵樹。ZNode 的節點路徑標識方式和Unix文件系統路徑非常相似,都是由一系列使用斜槓(/) 進行分割的路徑表示,開發人員可以向這個節點中寫入數據,也可以在節點下面創建子節點。如圖。
1.2 事務ID(ZXID)
1.2.1 什麼是事務
事務是對物理和抽象的應用狀態上的操作集合。在現在的計算機科學中,狹義上的事務通常指的是數據庫事務,一 般包含了一系列
對數據庫有序的讀寫操作,這些數據庫事務具有所謂的ACID特性,即原子性(Atomic)、一致性(Consistency)、隔離性(Isolation) 和持久性(Durability)。
1.2.2 ZooKeeper中的事務
在ZooKeeper中,事務是指能夠改變ZooKeeper服務器狀態的操作,我們也稱之爲事務操作或更新操作,一般包括數據節點創建與刪除、數據節點內容更新和客戶端會話創建與失效等操作。對於每一個事務請求,ZooKeeper都會爲其分配一個全局唯一的事務 ID,用ZXID來表示,通常是一個64位的數字。每一個ZXID對應一次更新操作,從這些ZXID中可以間接地識別出ZooKeeper處理這些更新操作請求的全局順序。
二、節點特性
2.1 節點類型
在ZooKeeper中,每個數據節點都是有生命週期的,其生命週期的長短取決於數據節點的節點類型。在ZooKeeper中,**節點類型可以分爲持久節點(PERSISTENT)、臨時節點(EPHEMERAL)、順序節點(SEQUENTIAL)**三大類,具體在節點創建過程中,通過組合使用,可以生成以下四種組合型節點類型:
2.1.1 持久節點(PERSISTENT)
持久節點是ZooKeeper中最常見的一種節點類型。所謂持久節點,是指該數據節點被創建後,就會一直存在於ZooKeeper服務器上,直到有刪除操作來主動清除這個節點。
2.1.2 持久順序節點(PERSISTENT_ SEQUENTIAL)
持久順序節點的基本特性和持久節點是-致的,額外的特性表現在順序性上。在ZooKeeper中,每個父節點都會爲它的第一級子節點維護一份順序,用於記錄下每個子節點創建的先後順序。基於這個順序特性,在創建子節點的時候,可以設置這個標記,那麼在創建節點過程中,ZooKeeper 會自動爲給定節點名加上一個數字後綴,作爲一個新的、完整的節點名。另外需要注意的是,這個數字後綴的上限是整型的最大值。
2.1.3 臨時節點(EPHEMERAL)
和持久節點不同的是,臨時節點的生命週期和客戶端的會話綁定在一起,也就是說,如果客戶端會話失效,那麼這個節點就會被自動清理掉。注意,這裏提到的是客戶端會話失效,而非TCP連接斷開。另外,ZooKeeper規定了不能基於臨時節點來創建子節點,即臨時節點只能作爲葉子節點。
2.1.4 臨時順序節點(EPHEMERAL_ SEQUENTIAL)
臨時順序節點的基本特性和臨時節點也是一致的,同樣是在臨時節點的基礎上,添加了順序的特性。
2.2 狀態信息
可以針對ZooKeeper上的數據節點進行數據的寫人和子節點的創建。事實上,每個數據節點除了存儲了數據內容之外,還存儲了數據節點本身的一些狀態信息。
[zk: localhost:2181(CONNECTED) 7] get /user
xiaoming
cZxid = 0x4
ctime = Sun Jan 26 18:36:52 CST 2020
mZxid = 0x4
mtime = Sun Jan 26 18:36:52 CST 2020
pZxid = 0x4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
上面是我創建了一個zk的節點。關於zk的安裝與使用,可以參考我的博客 Zookeeper的安裝與基本使用
狀態屬性 | 說 明 |
---|---|
czxid | 即Created ZXID,表示該數據節點被創建時的事務ID |
mzxid | Modified ZXID,表示該節點最後一次被更新時的事務ID |
ctime | CreatedTime,表示節點被創建的時間 |
mtime | Modified Time,表示該節點最後一次被更新的時間數據節點的版本號。 |
cversion | 子節點的版本號 |
aclVersion | 節點的ACL版本號 |
dataVersion | 數據的版本號 |
ephemeralOwner | 創建該臨時節點的會話的sessionID。如果該節點是持久節點,那麼這個屬性值爲0 |
datalength | 數據內容的長度 |
numChildren | 當前節點的子節點個數 |
pzxid | 表示該節點的子節點列表最後一次被修改時的事務ID。注意,只有子節點列表變更了纔會變更pzxid,子節點內容變更不會影響pzxid |
三、版本—保證分佈式數據原子性操作
ZooKeeper中爲數據節點引入了版本的概念,每個數據節點都具有三種類型的版本信息,對數據節點的任何更新操作都會引起版本號的變化。
Zookeeper中的版本
ZooKeeper中的版本概念和傳統意義上的軟件版本有很大的區別,它表示的是對數據節點的數據內容、子節點列表,或是節點ACL信息的修改次數,我們以其中的version這種版本類型爲例來說明。在一個數據節點/zk-book被創建完畢之後,節點的version值是0,表示的含義是“當前節點自從創建之後,被更新過0次”。如果現在對該節點的數據內容進行更新操作,那麼隨後,version的值就會變成1。同時需要注意的是,在上文中提到的關於version的說明,其表示的是對數據節點數據內容的變更次數,強調的是變更次數,因此即使前後兩次變更並沒有使得數據內容的值發生變化,version
的值依然會變更。
和樂觀鎖的版本一樣。
四、Watcher —數據變更的通知
4.1 Watcher的作用
ZooKeeper提供了分佈式數據的發佈/訂閱功能。一個典型的發佈/訂閱模型系統定義了一種一對多的訂閱關係,能夠讓多個訂閱者同時監聽某一個主題對象,當這個主題對象自身狀態變化時,會通知所有訂閱者,使它們能夠做出相應的處理。在ZooKeeper中,引入了Watcher機制來實現這種分佈式的通知功能。
ZooKeeper允許客戶端向服務端註冊一個Watcher監聽,當服務端的一些指定事件觸發了這個Watcher,那麼就會向指定客戶端發送一個事件通知來實現分佈式的通知功能。
從上圖中,可以看到,ZooKeeper 的Watcher 機制主要包括客戶端線程、WatchManager和ZooKeeper服務器三部分。
4.2 Watcher工作流程
在具體工作流程上,簡單地講,客戶端在向ZooKeeper服務器註冊Watcher的同時,會將Watcher對象存儲在客戶端的
WatchManager中。當ZooKeeper服務器端觸發Watcher事件後,會向客戶端發送通知,客戶端線程從WatchManager中取出對應的Watcher對象來執行回調邏輯。
4.3 Watcher的特性
4.3.1 一次性
無論是服務端還是客戶端,一旦一個Watcher 被觸發,ZooKeeper都會將其從相應的存儲中移除。因此,開發人員在Watcher的使用上要記住的一點是需要反覆註冊。這樣的設計有效地減輕了服務端的壓力。試想,如果註冊一個 Watcher之後一直有效,那麼,針對那些更新非常頻繁的節點,服務端會不斷地向客戶端發送事件通知,這無論對於網絡還是服務端性能的影響都非常大。
4.3.2 客戶端串行執行
客戶端Watcher回調的過程是一個串行同步的過程,這爲我們保證了順序,同時需要開發人員注意的一點是,千萬不要因爲一個Watcher 的處理邏輯影響了整個客戶端的Watcher回調。
4.3.3 輕量
WatchedEvent是ZooKeeper整個Watcher通知機制的最小通知單元,這個數據結構中只包含三部分內容:通知狀態、事件類型和節點路徑。也就是說,Watcher通知非常簡單,只會告訴客戶端發生了事件,而不會說明事件的具體內容。例如針對NodeDataChanged事件, ZooKeeper的Watcher只會通知客戶端指定數據節點的數據內容發生了變更,而對於原始數據以及變更後的新數據都無法從這個事件中直接獲取到,而是需要客戶端主動重新去獲取數據一這 也是ZooKeeper的Watcher機制的一個非常重要的特性。
另外,客戶端向服務端註冊Watcher的時候,並不會把客戶端真實的Watcher對象傳遞到服務端,僅僅只是在客戶端請求中使用boolean類型屬性進行了標記,同時服務端也僅僅只是保存了當前連接的ServerCnxn對象。如此輕量的Watcher機制設計,在網絡開銷和服務端內存開銷上都是非常廉價的。
五、ACL—保障數據的安全
ZooKeeper 作爲一個分佈式協調框架,其內部存儲的都是一些關乎分佈式系統運行時狀態的元數據,尤其是一些涉及分佈式鎖、Master選舉和分佈式協調等應用場景的數據,會直接影響基於ZooKeeper進行構建的分佈式系統的運行狀態。因此,如何有效地保障ZooKeeper中數據的安全,從而避免因誤操作而帶來的數據隨意變更導致的分佈式系統異常就顯得格外重要了。所幸的是,ZooKeeper提供了一套完善的ACL(Access Control List)權限控制機制來保障數據的安全。
5.1 UGO權限控制
提到權限控制,我們首先來看看大家都熟悉的、在Unix/Linux 文件系統中使用的,也是目前應用最廣泛的權限控制方式一一UGO (User. Group 和Others)權限控制機制。簡單地講,UGO就是針對一個文件或目錄,對創建者(User)、 創建者所在的組(Group)和其他用戶(Other) 分別配置不同的權限。從這裏可以看出,UGO其實是一種粗粒度的文件系統權限控制模式,利用UGO只能對三類用戶進行權限控制,即文件的創建者、創建者所在的組以及其他所有用戶,很顯然,UGO無法解決下面這個場景:
用戶U,創建了文件F,希望U所在的用戶組G擁有對F讀寫和執行的權限,另一個用戶組G2擁有讀權限,而另外一個用戶U3則沒有任何權限。接下去我們來看另外一種典型的權限控制方式: ACL。ACL,即訪問控制列表,是一種相對來說比較新穎且更細粒度的權限管理方式,可以針對任意用戶和組進行細粒度的權限控制。目前絕大部分Unix系統都已經支持了ACL方式的權限控制,Linux 也從2.6版本的內核開始支持這個特性。
5.2 ACL介紹
ZooKeeper的ACL權限控制和Unix/Linux操作系統中的ACL有一些區別,可以從三個方面來理解ACL機制,分別是:權限模式(Scheme)、授權對象(ID)和權限(Permission),通常使用“scheme:id:permission
” 來標識一個有效的ACL信息。
5.2.1 權限模式: Scheme
權限模式用來確定權限驗證過程中使用的檢驗策略。在ZooKeeper中,開發人員使用最多的就是以下四種權限模式。
5.2.1.1 IP
IP模式通過IP地址粒度來進行權限控制,例如配置了“ip:192.168.0.110”
, 即表示權限控制都是針對這個IP地址的。同時,IP模式也支持按照網段的方式進行配置,例如“ip: 192.168.0.1/24”
表示針對192.168.0.*
這個IP段進行權限控制。
5.2.1.2 Digest
Digest是最常用的權限控制模式,也更符合我們對於權限控制的認識,其以類似於“username:password"
形式的權限標識來進行權限配置,便於區分不同應用來進行權限控制。
當我們通過“ username:password”
形式配置了權限標識後,ZooKeeper 會對其先後進行兩次編碼處理,分別是SHA-1算法加密和BASE64 編碼,其具體實現由
DigestAuthenticationProvider.generateDigest(String idPassword)
函數進行封裝。
5.2.1.3 World
World是一種最開放的權限控制模式,從其名字中也可以看出,事實上這種權限控制方式幾乎沒有任何作用,數據節點的訪問權限對所有用戶開放,即所有用戶都可以在不進行任何權限校驗的情況下操作ZooKeeper,上的數據。另外,World模式也可以看作是一種特殊的Digest模式,它只有一個權限標識,即“ world:anyone"
。
5.2.1.4 Super
Super模式,顧名思義就是超級用戶的意思,也是一種特殊的Digest模式。在Super模式下,超級用戶可以對任意ZooKeeper上的數據節點進行任何操作。
5.2.2 授權對象: ID
授權對象指的是權限賦予的用戶或一一個指定實體,例如IP地址或是機器等。在不同的權限模式下,授權對象是不同的。
各個權限模式和授權對象之間的對應關係
權限模式 | 授權對象 |
---|---|
ip | 通常是一個IP地址或是IP段,例如“192.168.0.110” 或“192.168.0.1/24” |
Digest | 自定義,通常是“username:BASE64(SHA-1(username:password))”,例如‘ foo: kWN6aNSbjcKWPqjiV7cg0N24raU=" |
World | 只有一個ID:“ anyone’ |
Super | 與Digest 模式一致 |
5.2.3 權限: Permission
權限就是指那些通過權限檢查後可以被允許執行的操作。在ZooKeeper中,所有對數據的操作權限分爲以下五大類:
CREATE(C)
:數據節點的創建權限,允許授權對象在該數據節點下創建子節點。DELETE(D)
:子節點的刪除權限,允許授權對象刪除該數據節點的子節點。READ(R)
:數據節點的讀取權限,允許授權對象訪問該數據節點並讀取其數據內容或子節點列表等。WRITE(W)
:數據節點的更新權限,允許授權對象對該數據節點進行更新操作。ADMIN (A)
:數據節點的管理權限,允許授權對象對該數據節點進行ACL相關的設置操作。
5.3 設置ACL的方法
通過zkCli腳本登錄ZooKeeper服務器後,可以通過兩種方式進行ACL的設置。
一種是在數據節點創建的同時進行ACL權限的設置,命令格式如下:
create [-s] [-e] path data acl
另一種方式則是使用setAcl命令單獨對已經存在的數據節點進行ACL設置:
setAcl path acl