前言
在昨天,我們給大家基本介紹了Dubbo,文中反復提到了Zookeeper,那么它到底是什么呢,這篇文章我們將從Dubbo層面去了解Zookeeper,不做全面講解,畢竟這是Dubbo教程啊~
Zookeeper的概念
官方給出的文檔顯示:
ZooKeeper是一種為分布式應用所設計的高可用、高性能且一致的開源協調服務,它提供了一項基本服務:分布式鎖服務。由於ZooKeeper的開源特性,后來我們的開發者在分布式鎖的基礎上,摸索了出了其他的使用方法:配置維護、組服務、分布式消息隊列、分布式通知/協調等。
博主針對Dubbo給出的解釋:
-
一個類似於58同城的信息管理平台,用於給消費者和服務者呈現自己信息的地方。
-
信息內容盡量簡短,不適合存放長篇大論,也就是說它不可能承擔博客該有的功能。
-
他能平滑的解決雙方之間脫離關系和增長關系。舉個例子,我在zookeeper上說需要房子,有N個銷售在zookeeper上發布了消息說他有房子。然后我本來要找A的,可是A的房子出售了,發布的信息就刪除了,於是zookeeper主動告訴我,你去找B吧,B的房子還在。(集群管理,負載均衡相比nginx無需重啟更加平滑)
注意:ZooKeeper性能上的特點決定了它能夠用在大型的、分布式的系統當中。從可靠性方面來說,它並不會因為一個節點的錯誤而崩潰。除此之外,它嚴格的序列訪問控制意味着復雜的控制原語可以應用在客戶端上。ZooKeeper在一致性、可用性、容錯性的保證,也是ZooKeeper的成功之處,它獲得的一切成功都與它采用的協議——Zab協議是密不可分的,這些內容將會在后面介紹。
Zookeeper的數據模型
ZooKeeper擁有一個層次的命名空間,這個和標准的文件系統非常相似,如下圖所示。

從圖中我們可以看出ZooKeeper的數據模型,在結構上和標准文件系統的非常相似,都是采用這種樹形層次結構,ZooKeeper樹中的每個節點被稱為—Znode。和文件系統的目錄樹一樣,ZooKeeper樹中的每個節點可以擁有子節點。但也有不同之處:
(1) 引用方式
Zonde通過路徑引用,如同Unix中的文件路徑。路徑必須是絕對的,因此他們必須由斜杠字符來開頭。除此以外,他們必須是唯一的,也就是說每一個路徑只有一個表示,因此這些路徑不能改變。在ZooKeeper中,路徑由Unicode字符串組成,並且有一些限制。字符串”/zookeeper”用以保存管理信息,比如關鍵配額信息。
(2) Znode結構
ZooKeeper命名空間中的Znode,兼具文件和目錄兩種特點。既像文件一樣維護着數據、元信息、ACL、時間戳等數據結構,又像目錄一樣可以作為路徑標識的一部分。圖中的每個節點稱為一個Znode。 每個Znode由3部分組成:
① stat:此為狀態信息, 描述該Znode的版本, 權限等信息
② data:與該Znode關聯的數據
③ children:該Znode下的子節點
ZooKeeper雖然可以關聯一些數據,但並沒有被設計為常規的數據庫或者大數據存儲,相反的是,它用來管理調度數據,比如分布式應用中的配置文件信息、狀態信息、匯集位置等等。這些數據的共同特性就是它們都是很小的數據,通常以KB為大小單位。ZooKeeper的服務器和客戶端都被設計為嚴格檢查並限制每個Znode的數據大小至多1M,但常規使用中應該遠小於此值。
(3) 數據訪問
ZooKeeper中的每個節點存儲的數據要被原子性的操作。也就是說讀操作將獲取與節點相關的所有數據,寫操作也將替換掉節點的所有數據。另外,每一個節點都擁有自己的ACL(訪問控制列表),這個列表規定了用戶的權限,即限定了特定用戶對目標節點可以執行的操作。
(4) 節點類型
ZooKeeper中的節點有兩種,分別為臨時節點和永久節點。節點的類型在創建時即被確定,並且不能改變。
① 臨時節點:該節點的生命周期依賴於創建它們的會話。一旦會話(Session)結束,臨時節點將被自動刪除,當然可以也可以手動刪除。雖然每個臨時的Znode都會綁定到一個客戶端會話,但他們對所有的客戶端還是可見的。另外,ZooKeeper的臨時節點不允許擁有子節點。
② 永久節點:該節點的生命周期不依賴於會話,並且只有在客戶端顯示執行刪除操作的時候,他們才能被刪除。
(5) 順序節點
當創建Znode的時候,用戶可以請求在ZooKeeper的路徑結尾添加一個遞增的計數。這個計數對於此節點的父節點來說是唯一的,它的格式為”%10d”(10位數字,沒有數值的數位用0補充,例如”0000000001”)。當計數值大於232-1時,計數器將溢出。
(6) 觀察
客戶端可以在節點上設置watch,我們稱之為監視器。當節點狀態發生改變時(Znode的增、刪、改)將會觸發watch所對應的操作。當watch被觸發時,ZooKeeper將會向客戶端發送且僅發送一條通知,因為watch只能被觸發一次,這樣可以減少網絡流量。
Zookeeper的分布式鎖
在分布式上,如果A要調用B的方法C,C方法也要加鎖,但這個鎖不能想單服務器那樣加,因為這個是分布式調用的方法,不一樣。就像事務一樣,單服務器上的事務和分布式事務不一樣。zookeeper提供了一個分布式同步(鎖)的方法,使用其提供的,客戶可以省了很多事。
咳咳,這種東西一開始就講,講了你們也聽不懂。索性放到后面去講,今天我們就先入個門吧,分布式鎖到此為止。
Zookeeper集群模式
角色
Zookeeper除了能管理客戶端集群,它本身也能構建集群來實現高可用,角色主要有以下三類,如下表所示:
系統模型如圖所示:
設計目的
1.最終一致性:client不論連接到哪個Server,展示給它都是同一個視圖,這是zookeeper最重要的性能。
2 .可靠性:具有簡單、健壯、良好的性能,如果消息m被到一台服務器接受,那么它將被所有的服務器接受。
3 .實時性:Zookeeper保證客戶端將在一個時間間隔范圍內獲得服務器的更新信息,或者服務器失效的信息。但由於網絡延時等原因,Zookeeper不能保證兩個客戶端能同時得到剛更新的數據,如果需要最新數據,應該在讀數據之前調用sync()接口。
4 .等待無關(wait-free):慢的或者失效的client不得干預快速的client的請求,使得每個client都能有效的等待。
5.原子性:更新只能成功或者失敗,沒有中間狀態。
6 .順序性:包括全局有序和偏序兩種:全局有序是指如果在一台服務器上消息a在消息b前發布,則在所有Server上消息a都將在消息b前被發布;偏序是指如果一個消息b在消息a后被同一個發送者發布,a必將排在b前面。
工作原理
Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分 別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和 leader的狀態同步以后,恢復模式就結束了。狀態同步保證了leader和Server具有相同的系統狀態。
為了保證事務的順序一致性,zookeeper采用了遞增的事務id號(zxid)來標識事務。所有的提議(proposal)都在被提出的時候加上 了zxid。實現中zxid是一個64位的數字,它高32位是epoch用來標識leader關系是否改變,每次一個leader被選出來,它都會有一個 新的epoch,標識當前屬於那個leader的統治時期。低32位用於遞增計數。
每個Server在工作過程中有三種狀態:
- LOOKING:當前Server不知道leader是誰,正在搜尋
- LEADING:當前Server即為選舉出來的leader
- FOLLOWING:leader已經選舉出來,當前Server與之同步
工作流程
Leader工作流程
Leader主要有三個功能:
1 .恢復數據;
2 .維持與Learner的心跳,接收Learner請求並判斷Learner的請求消息類型;
3 .Learner的消息類型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根據不同的消息類型,進行不同的處理。
PING消息是指Learner的心跳信息;REQUEST消息是Follower發送的提議信息,包括寫請求及同步請求;ACK消息是 Follower的對提議的回復,超過半數的Follower通過,則commit該提議;REVALIDATE消息是用來延長SESSION有效時間。
Leader的工作流程簡圖如下所示,在實際實現中,流程要比下圖復雜得多,啟動了三個線程來實現功能。
Follower工作流程
Follower主要有四個功能:
- 向Leader發送請求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
2 .接收Leader消息並進行處理;
3 .接收Client的請求,如果為寫請求,發送給Leader進行投票;
4 .返回Client結果。
Follower的消息循環處理如下幾種來自Leader的消息:
1 .PING消息: 心跳消息;
2 .PROPOSAL消息:Leader發起的提案,要求Follower投票;
3 .COMMIT消息:服務器端最新一次提案的信息;
4 .UPTODATE消息:表明同步完成;
5 .REVALIDATE消息:根據Leader的REVALIDATE結果,關閉待revalidate的session還是允許其接受消息;
6 .SYNC消息:返回SYNC結果到客戶端,這個消息最初由客戶端發起,用來強制得到最新的更新。
Follower的工作流程簡圖如下所示,在實際實現中,Follower是通過5個線程來實現功能的。
observer
bserver流程和Follower的唯一不同的地方就是observer不會參加leader發起的投票。但是可以觀察狀態,有效提高集群的效率,畢竟在多台server下,選舉是需要浪費資源的。
