?ZooKeeper是一個分布式的應用程序協調服務。
?
2 ZooKeeper的工作原理
Zookeeper 的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab(Zookeeper Atomic Broadcast)協議。Zab協議有兩種模式,它們分別是恢復模式(recovery選主)和?廣播模式(broadcast同步)。當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和leader的狀態同步以 后,恢復模式就結束了。狀態同步保證了leader和Server具有相同的系統狀態。
?
?1、ZooKeeper數據模型:
類似于一個標準的文件系統,具有層次關系的數據結構
每個子目錄項如NameService都被稱作為znode。
ZNode根據其本身的特性,可以分為下面兩類:
Regular ZNode: 常規型ZNode,
Ephemeral ZNode: (?'fem(?)r(?)l)(臨時的)類型的目錄節點不能有子節點目錄。
Zookeeper的客戶端和服務器通信采用長連接方式,每個客戶 端和服務器通過心跳來保持連接,這個連接狀態稱為session,如果znode是臨時節點,這個session失效,znode也就刪除了。(3s/一次,200次)。
如果Client因為Timeout和Zookeeper Server失去連接,client處在CONNECTING狀態,會自動嘗試再去連接Server,如果在session有效期內再次成功連接到某個Server,則回到CONNECTED狀態。
?
2、ZooKeeper Watch:
?
????Zookeeper從設計模式的角度來看,是一個基于觀察者設計模式設計的。簡單來說就是
?Client可以在某個ZNode上設置一個Watcher,來Watch該ZNode上的變化。如果該ZNode上有相應的變化,就會觸發這個Watcher,把相應的事件通知給設置Watcher的Client。需要注意的是,ZooKeeper中的Watcher是一次性的,即觸發一次就會被取消,如果想繼續Watch的話,需要客戶端重新設置Watcher。
?
3、?ZooKeeper特性?:
?
???讀、寫(更新)模式:
?
??在ZooKeeper集群中,讀可以從任意一個ZooKeeper Server讀。寫的請求會先Forwarder到Leader,然后由Leader來通過ZooKeeper中的原子廣播協議,將請求廣播給所有的Follower,Leader收到一半以上的寫成功的消息后,就認為該寫成功了,就會將該寫進行持久化,并告訴客戶端寫成功了。
?
???FIFO
對于每一個ZooKeeper客戶端而言,所有的操作都是遵循FIFO順序的,這一特性是由下面兩個基本特性來保證的:一是ZooKeeper Client與Server之間的網絡通信是基于TCP,TCP保證了Client/Server之間傳輸包的順序;二是ZooKeeper Server執行客戶端請求也是嚴格按照FIFO順序的。
為 了保證事務的順序一致性,zookeeper采用了遞增的事務id號(zxid)來標識事務。所有的提議(proposal)都在被提出的時候加上了 zxid。實現中zxid是一個64位的數字,它高32位是?用來標識leader關系是否改變,每次一個leader被選出來,它都會有一個新 的epoch,標識當前屬于那個leader的統治時期。低32位用于遞增計數。
?
?ZooKeeper典型應用場景
- 名字服務(NameService)?:
每個ZNode都可以由其路徑唯一標識,路徑本身也比較簡潔直觀,另外ZNode上還可以存儲少量數據,這些都是實現統一的NameService的基礎。通過簡單的名字,訪問對應的服務器集群。
?
- 配置管理(Configuration Management)?:
?
?
?
一:分布式互斥鎖?
在傳統的應用程序中,線程、進程的同步,都可以通過操作系統提供的機制來完成。但是在分布式系統中,多個進程之間的同步,操作系統層面就無能為力了。
zookeeper中,并沒有像JAVA里一樣有Synchronized或者是ReentrantLock機制來實現鎖機制,但是在zookeeper中,實現起來更簡單:我們可以講將zk的一個數據節點代表一個鎖,當多個客戶端同時調用create()節點創建節點的時候,zookeeper會保證只會有一個客戶端創建成功,那么我們就可以讓這個創建成功的客戶端讓其持有鎖,而其它的客戶端則注冊Watcher監聽當持有鎖的客戶端釋放鎖后,監聽的客戶端就會收到Watcher通知,然后再去試圖獲取鎖,這樣反復即可。
Zookeeper的三種角色:
1.leader和follower?
?
? ? ? ZooKeeper需要在所有的服務(可以理解為服務器)中選舉出一個Leader,然后讓這個Leader來負責管理集群。此時,集群中的其它服務器則 成為此Leader的Follower。并且,當Leader故障的時候,需要ZooKeeper能夠快速地在Follower中選舉出下一個 Leader。這就是ZooKeeper的Leader機制,下面我們將簡單介紹在ZooKeeper中,Leader選舉(Leader Election)是如何實現的。?
此操作實現的核心思想是:首先創建一個EPHEMERAL目錄節點,例如“/election”。然后。每一個ZooKeeper服務器在此目錄 下創建一個SEQUENCE|EPHEMERAL類型的節點,例如“/election/n_”。在SEQUENCE標志下,ZooKeeper將自動地 為每一個ZooKeeper服務器分配一個比前一個分配的序號要大的序號。此時創建節點的ZooKeeper服務器中擁有最小序號編號的服務器將成為 Leader。
在實際的操作中,還需要保障:當Leader服務器發生故障的時候,系統能夠快速地選出下一個ZooKeeper服務器作為Leader。一個簡 單的解決方案是,讓所有的follower監視leader所對應的節點。當Leader發生故障時,Leader所對應的臨時節點將會自動地被刪除,此 操作將會觸發所有監視Leader的服務器的watch。這樣這些服務器將會收到Leader故障的消息,并進而進行下一次的Leader選舉操作。但 是,這種操作將會導致“從眾效應”的發生,尤其當集群中服務器眾多并且帶寬延遲比較大的時候,此種情況更為明顯。
在Zookeeper中,為了避免從眾效應的發生,它是這樣來實現的:每一個follower對follower集群中對應的比自己節點序號小一 號的節點(也就是所有序號比自己小的節點中的序號最大的節點)設置一個watch。只有當follower所設置的watch被觸發的時候,它才進行 Leader選舉操作,一般情況下它將成為集群中的下一個Leader。很明顯,此Leader選舉操作的速度是很快的。因為,每一次Leader選舉幾 乎只涉及單個follower的操作。
2.Observer
? ? ? observer的行為在大多數情況下與follower完全一致, 但是他們不參加選舉和投票, 而僅僅接受(observing)選舉和投票的結果.
Zookeeper集群,選舉機制
?
?
zookeeper選舉機制
FastLeaderElection算法通過異步的通信方式來收集其它節點的選票,同時在分析選票時又根據投票者的當前狀態來作不同的處理,以加快Leader的選舉進程。???? if (n.epoch > logicalclock) { logicalclock = n.epoch; recvset.clear(); if(totalOrderPredicate(n.leader, n.zxid,getInitId(), getInitLastLoggedZxid())) updateProposal(n.leader, n.zxid); else updateProposal(getInitId(),getInitLastLoggedZxid()); sendNotifications();
|
?