zookeeper詳解(一) -- 基本結構
1、zookeeper是什麼
ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是Google的Chubby一個開源的實現,是Hadoop的重要元件,CDH版本中更是使用它進行Namenode的協調控制。它是一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、名字服務、分散式同步、組服務等。ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。
zookeeper到底能為我們的分散式系統做什麼事情呢:
- 管理系統中獨特的/統一的資訊:
一個分散式系統的各節點可能需要一個規範的、各節點的唯一的命名(例如節點名、CPU編號等),ZK可以實現這個的應用場景。
各個節點也會有一致的資訊,例如每個節點的主配置資訊。為了管理方便,新加入的節點也需要快速同步這些資訊。使用ZK可以方便的做到。
- 叢集狀態監控和通知:
分散式系統中的每個節點需要知道整個系統的狀態、知道系統中每個節點的狀態:當有新節點加入時它需要知道、當有節點出現故障時它需要知道、當有節點退出時它需要知道。ZK就是這樣一個“通知工具”。
- 協調資源搶佔(鎖):
當分散式系統的多個節點試圖同時搶佔唯一資源時(例如同時寫入一個檔案),就需要對這個唯一資源的使用進行協調。這是ZK的“協調者”功能。
- 分派計算任務:
如何協調1000個需要同時處理的任務到分散式系統的13個節點?如何保證執行失敗的任務能被重新執行?如何在某個節點崩潰的情況下,接管其正在處理的任務?
2 ,Zookeeper的基本概念
(1) 角色
Zookeeper中的角色主要有以下三類,如下表所示:
系統模型如圖所示:
(2) 設計目的
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前面。
3 , 特點
(1)Zookeeper是可重用的
ZooKeeper Service
組成Zookeeper的各個伺服器必須要能相互通訊。他們在記憶體中儲存了伺服器狀態,也儲存了操作的日誌,並且持久化快照。只要大多數的伺服器是可用的,那麼Zookeeper就是可用的。
客戶端連線到一個Zookeeper伺服器,並且維持TCP連線。並且傳送請求,獲取回覆,獲取事件,並且傳送連線訊號。如果這個TCP連線斷掉了,那麼客戶端可以連線另外一個伺服器。
(2)Zookeeper是有序的Zookeeper使用數字來對每一個更新進行標記。這樣能保證Zookeeper互動的有序。後續的操作可以根據這個順序實現諸如同步操作這樣更高更抽象的服務。
(3)Zookeeper是高效的Zookeeper的高效更表現在以讀為主的系統上。Zookeeper可以在千臺伺服器組成的讀寫比例大約為10:1的分佈系統上表現優異。
(4)資料結構和分等級的名稱空間Zookeeper的名稱空間的結構和檔案系統很像。一個名字和檔案一樣使用/的路徑表現,zookeeper的每個節點都是被路徑唯一標識
ZooKeeper's Hierarchical Namespace
4、zookeeper的儲存結構
zookeeper中的資料是按照“樹”結構進行儲存的。而且znode節點還分為4中不同的型別。
(1)、znode
根據本小結第一部分的描述,很顯然zookeeper叢集自身維護了一套資料結構。這個儲存結構是一個樹形結構,其上的每一個節點,我們稱之為“znode”。如下如所示:
-
每一個znode預設能夠儲存1MB的資料(對於記錄狀態性質的資料來說,夠了)
-
可以使用zkCli命令,登入到zookeeper上,並通過ls、create、delete、sync等命令操作這些znode節點
-
znode除了名稱、資料以外,還有一套屬性:zxid。這套zid與時間戳對應,記錄zid不同的狀態(後續我們將用到)
那麼每個znode結構又是什麼樣的呢?如下圖所示:
此外,znode還有操作許可權。如果我們把以上幾類屬性細化,又可以得到以下屬性的細節:
- 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子節點個數。
(2)、znode中的存在型別
我們知道了zookeeper內部維護了一套資料結構:由znode構成的集合,znode的集合又是一個樹形結構。每一個znode又有很多屬性進行描述。並且znode的存在性還分為四類,如下如所示:
znode是由客戶端建立的,它和建立它的客戶端的內在聯絡,決定了它的存在性:
-
PERSISTENT-持久化節點:建立這個節點的客戶端在與zookeeper服務的連線斷開後,這個節點也不會被刪除(除非您使用API強制刪除)。
-
PERSISTENT_SEQUENTIAL-持久化順序編號節點:當客戶端請求建立這個節點A後,zookeeper會根據parent-znode的zxid狀態,為這個A節點編寫一個全目錄唯一的編號(這個編號只會一直增長)。當客戶端與zookeeper服務的連線斷開後,這個節點也不會被刪除。
-
EPHEMERAL-臨時目錄節點:建立這個節點的客戶端在與zookeeper服務的連線斷開後,這個節點(還有涉及到的子節點)就會被刪除。
-
EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點:當客戶端請求建立這個節點A後,zookeeper會根據parent-znode的zxid狀態,為這個A節點編寫一個全目錄唯一的編號(這個編號只會一直增長)。當建立這個節點的客戶端與zookeeper服務的連線斷開後,這個節點被刪除。
-
另外,無論是EPHEMERAL還是EPHEMERAL_SEQUENTIAL節點型別,在zookeeper的client異常終止後,節點也會被刪除。
圖 1 Zookeeper 資料結構
Zookeeper 這種資料結構有如下這些特點:
- 每個子目錄項如 NameService 都被稱作為 znode,這個 znode 是被它所在的路徑唯一標識,如 Server1 這個 znode 的標識為 /NameService/Server1
- znode 可以有子節點目錄,並且每個 znode 可以儲存資料,注意 EPHEMERAL 型別的目錄節點不能有子節點目錄
- znode 是有版本的,每個 znode 中儲存的資料可以有多個版本,也就是一個訪問路徑中可以儲存多份資料
- znode 可以是臨時節點,一旦建立這個 znode 的客戶端與伺服器失去聯絡,這個 znode 也將自動刪除,Zookeeper 的客戶端和伺服器通訊採用長連線方式,每個客戶端和伺服器通過心跳來保持連線,這個連線狀態稱為 session,如果 znode 是臨時節點,這個 session 失效,znode 也就刪除了
- znode 的目錄名可以自動編號,如 App1 已經存在,再建立的話,將會自動命名為 App2
- znode 可以被監控,包括這個目錄節點中儲存的資料的修改,子節點目錄的變化等,一旦變化可以通知設定監控的客戶端,這個是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基於這個特性實現的,後面在典型的應用場景中會有例項介紹
(3)、zk中的選舉FastLeaderELection
我們已經知道了一個zookeeper叢集中,有一個處於leader身份的節點,其他的節點都是flower狀態。那麼一個leader是怎麼產生的呢?這就是zookeeper中的選舉規則,預設的選舉規則稱為:FastLeaderELection(網上的資料還有提到另外的選舉演算法,實際上它們的核心思想都是一樣的)
3.1、選舉演算法的中心思想
網上的資料有使用純文字進行演算法描述的,也有使用流程圖進行演算法描述的,但是如果讀者不仔細看,還是容易昏頭轉向,這裡我們使用一張過程圖和文字相結合的方式對FastLeaderELection選舉演算法進行描述。實際上FastLeaderELection說的中心思想無外乎以下幾個關鍵點:
-
全天下我最牛,在我沒有發現比我牛的推薦人的情況下,我就一直推舉我當leader。第一次投票那必須推舉我自己當leader。
-
每當我接收到其它的被推舉者,我都要回饋一個資訊,表明我還是不是推舉我自己。如果被推舉者沒我大,我就一直推舉我當leader,是我是我還是我!
-
我有一個票箱, 和我屬於同一輪的投票情況都在這個票箱裡面。一人一票 重複的或者過期的票,我都不接受。
-
一旦我不再推舉我自己了(這時我發現別人推舉的人比我推薦的更牛),我就把我的票箱清空,重新發起一輪投票(這時我的票箱一定有兩票了,都是選的我認為最牛的人)。
-
一旦我發現收到的推舉資訊中投票輪要高於我的投票輪,我也要清空我的票箱。並且還是投當初我覺得最牛的那個人(除非當前的人比我最初的推薦牛,我就順帶更新我的推薦)。
-
不斷的重複上面的過程,不斷的告訴別人“我的投票是第幾輪”、“我推舉的人是誰”。直到我的票箱中“我推舉的最牛的人”收到了不少於 N /2 + 1的推舉投票。
-
這時我就可以決定我是flower還是leader了(如果至始至終都是我最牛,那我就是leader咯,其它情況就是follower咯)。並且不論隨後收到誰的投票,都向它直接反饋“我的結果”。
3.2、網上的資料
上圖是網路上的一張選舉過程圖,步驟是怎麼樣的,筆者我就不再多說了,只希望這個能輔助大家更好的理解選舉過程。
哦,現在您知道為什麼zookeeper在少於 N + 1 / 2的節點處於工作狀態的情況下會崩潰了吧。因為,無論怎麼選也沒有任何節點能夠獲得 N + 1 / 2 的票數。