ZooKeeper(1)--ZooKeeper概述
參考於ZooKeeper學習第一期---Zookeeper簡單介紹
Zookeeper是什麼?
ZooKeeper是一種為分散式應用所設計的高可用、高效能且一致的開源協調服務,它提供了一項基本服務:分散式鎖服務。
協調服務--"鎖"
Zookeeper主要應用於分散式系統,協調分散式系統下不同機器的多個執行緒對臨界資源呼叫.
如果是在同一臺機器中,不同執行緒之間的協調是比較容易的.可以對臨界資源加鎖.當一個執行緒要使用這個臨界資源的時候,要先獲取鎖,並一直獨自享有這個資源,其他程序是無法使用這個臨界資源.直到這個執行緒呼叫完這個資源或發生了異常,就會將鎖釋放掉,這時其他執行緒才可以再去獲取這個鎖
但是這個鎖在分散式系統中就沒有這麼"好用"了.
分散式系統所面臨的問題
在分散式系統中,不同的系統之間的聯絡是通過網路來進行的,這就涉及到一個問題:網路穩定性問題.
在同一臺機器中,一個執行緒呼叫服務只有兩種情況:呼叫成功和呼叫失敗,丟擲異常.但是在分散式系統,由於網路的不穩定,會出現一種情況,在一個執行緒獲取到鎖並在呼叫完之後,傳送資訊給伺服器,告訴伺服器已經完成任務,可以釋放鎖,但是由於網路原因,這個資訊丟失了,而其他執行緒一直等待著鎖的釋放,導致了死鎖.
還有一種情況,需要A,B兩個執行緒按順序呼叫服務C,在時間上 A先呼叫,B後呼叫,但是由於網路原因
其次,在分散式環境中為了提升可靠性,我們往往會部署多套服務,但是如何在多套服務中達到一致性,這在同一臺機器上多個程序之間的同步相對來說比較容易辦到,但在分散式環境中確實一個大難題.
Zookeeper使用了分散式鎖來解決這些問題.
Zookeeper概述
那麼Zookeeper是如何實現分散式鎖的呢?除此之外,Zookeeper還通過什麼方式實現了配置維護、組服務、分散式訊息佇列、分散式通知/協調等服務.
Zookeeper設計了一種資料結構—Znode,然後在該資料結構的基礎上定義了一些原語,也就是一些關於該資料結構的一些操作。有了這些資料結構和原語還不夠,因為我們的
Zookeeper的資料模型Znode
Zookeeper的結構和檔案系統非常相似,都是一種樹形結構.
ZooKeeper樹中的每個節點被稱為—Znode。和檔案系統的目錄樹一樣,ZooKeeper樹中的每個節點可以擁有子節點。但也有不同之處:
引用方式
Znode通過路徑訪問,而且必須是絕對路徑,開頭必須為"/",而不能是相對路徑,比如說想訪問Storage節點,則必須是/Baidu/Yun/Storage.字串"/zookeeper"用以儲存管理資訊,比如關鍵配額資訊。
Znode結構
Znode兼具檔案與目錄的屬性,即可以當做一個檔案:儲存一些資料,原資訊,ACL,時間戳等資訊,也可以當做一個目錄:作為路徑標識的一部分,並擁有子節點.
而Znode由三部分組成:
stat:狀態資訊,描述Znode的版本,許可權的資訊
data:儲存一些資料.
children:儲存該節點的子節點.
Znode雖然又可以儲存資料的部分,但其一般不用於儲存一些普通的資料,其通常被用於儲存一些對分散式系統比較重要的排程資訊,如分散式應用中的配置檔案資訊、狀態資訊、彙集位置等等,而且Znode的資料大小被限制在1M以內,但常規使用中,我們儲存的資料應該遠遠小於此數值.
資料訪問
讀操作將獲取與節點相關的所有資料,寫操作也將替換掉節點的所有資料。另外,每一個節點都擁有自己的ACL(訪問控制列表),這個列表規定了使用者的許可權,即限定了特定使用者對目標節點可以執行的操作。
節點型別
Zookeeper中的節點有兩種,分別為臨時節點(ephemeral)和永久節點(persistent).節點的型別在建立的時候就會被確定,而且不能修改.
臨時節點:該節點的生命週期依賴於會話,一旦會話(session)結束,臨時節點將自動刪除,此外,臨時節點不允許有子節點.
永久節點:該節點永遠存在,不依賴域會話,只能被手動刪除,允許有子節點,且子節點可以是臨時節點,也可以是永久節點.
順序節點:當建立Znode的時候,使用者可以請求在ZooKeeper的路徑結尾新增一個遞增的計數。這個計數對於此節點的父節點來說是唯一的,它的格式為"%10d"(10位數字,沒有數值的數位用0補充,例如"0000000001")。當計數值大於232-1時,計數器將溢位。
觀察
客戶端可以在節點上設定監視器,即watch,其作用是在節點發生變化(增刪改查)的時候,會向客戶端傳送相對應的通知,注意的是,這個通知會且只會傳送一次.
Zookeeper的版本資訊
Zookeeper主要通過zxid屬性來維護版本資訊,致使ZooKeeper節點狀態改變的每一個操作都將使節點接收到一個Zxid格式的時間戳,並且這個時間戳全域性有序。也就是說,每個對節點的改變都將產生一個唯一的Zxid。如果Zxid1的值小於Zxid2的值,那麼Zxid1所對應的事件發生在Zxid2所對應的事件之前。
實際上,ZooKeeper的每個節點維護者三個Zxid值,為別為:cZxid、mZxid、pZxid。
① cZxid: 是節點的建立時間所對應的Zxid格式時間戳。
② mZxid:是節點的修改時間所對應的Zxid格式時間戳。
實現中Zxid是一個64為的數字,它高32位是epoch用來標識leader關係是否改變,每次一個leader被選出來,它都會有一個 新的epoch。低32位是個遞增計數。 (2) 版本號
對節點的每一個操作都將致使這個節點的版本號增加。每個節點維護著三個版本號,他們分別為:
① version:節點資料版本號
② cversion:子節點版本號
③ aversion:節點所擁有的ACL版本號
Zookeeper的節點屬性
czxid |
節點被建立的zxid |
mzxid |
節點被修改的zxid |
ctime |
節點被建立的時間 |
mtime |
節點被修改的時間 |
version |
節點被修改的版本號 |
cversion |
節點所擁有的子節點被修改的版本號 |
aversion |
節點的ACL(許可權管理)被修改的版本號 |
ephemeralowner |
如果該節點為臨時節點,則為該節點擁有者的會話ID,否則為0 |
dataLength |
節點數長度 |
numChildren |
節點用的子節點長度 |
pzxid |
該節點的子節點(或該節點)的最近一次 建立 / 刪除 的時間戳對應,只與 本節點 / 該節點的子節點,有關;與孫子節點無關。 |
Watch觸發器
ZooKeeper可以為所有的讀操作設定watch,這些讀操作包括:exists()、getChildren()及getData()。watch事件是一次性的觸發器,每次都需要重新註冊,並且客戶端在會話異常結束時不會收到任何通知,當watch的物件狀態發生改變時,將會觸發此物件上watch所對應的事件。watch事件將被非同步地傳送給客戶端.
對watch來說,有三個主要特性:
一次性觸發:觀察事件會在觀察的資料改變時被主動傳送給客戶端。舉個例子,如果一個客戶端呼叫了getData("/znode1", true),也就是在/znode1上設定了一個觀察者,在這之後,如果/znode1發生了改變或者被刪除了,這個客戶端會受到觀察事件的提醒,但是,如果之後/znode1又發生了改變或者刪除,這個客戶端是不會收到事件提醒的了。
有序地傳送給客戶端:watch事件非同步傳送至觀察者。比如說client執行一次寫操作,節點資料內容發生變化,操作返回後,而watch事件可能還在發往client的路上這種情況下,但ZooKeeper保證了一個順序:一個客戶端在收到watch事件之前,一定不會看到它設定過watch的節點的變動。網路時延和其他因素可能會導致不同的客戶端看到watch和更新返回值的時間不同。但關鍵點是,從客戶端接收到的watch事件順序一定和ZooKeeper服務所看到的事件順序是一致的。
觀察者觀察的資料:ZooKeeper中一個節點發生改變會有不同的方式。也就是,在zk服務端中,維護著兩個觀察者列表:資料觀察者、子節點觀察者。getData()和exists()設定的是資料觀察者,getChildren()設定的是子節點觀察者。
① exists操作上的watch,在被監視的Znode建立、刪除或資料更新時被觸發。
② getData操作上的watch,在被監視的Znode刪除或資料更新時被觸發。在被建立時不能被觸發,因為只有Znode一定存在,getData操作才會成功。
③ getChildren操作上的watch,在被監視的Znode的子節點建立或刪除,或是這個Znode自身被刪除時被觸發。可以通過檢視watch事件型別來區分是Znode,還是他的子節點被刪除:NodeDelete表示Znode被刪除,NodeDeletedChanged表示子節點被刪除。
Zookeeper中的角色
» 領導者(leader),負責進行投票的發起和決議,更新系統狀態
» 學習者(learner),包括跟隨者(follower)和觀察者(observer),follower用於接受客戶端請求並想客戶端返回結果,在選主過程中參與投票
» Observer可以接受客戶端連線,將寫請求轉發給leader,但observer不參加投票過程,只同步leader的狀態,observer的目的是為了擴充套件系統,提高讀取速度
» 客戶端(client),請求發起方
Zookeep節點資料操作流程
1.在Client向Follwer發出一個寫的請求
2.Follwer把請求傳送給Leader
3.Leader接收到以後開始發起投票並通知Follwer進行投票
4.Follwer把投票結果傳送給Leader
5.Leader將結果彙總後如果需要寫入,則開始寫入同時把寫入操作通知給Leader,然後commit;
6.Follwer把請求結果返回給Client
• Follower主要有四個功能:
• 1. 向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結果到客戶端,這個訊息最初由客戶端發起,用來強制得到最新的更新