ZooKeeper的典型应用
Zookeeper是一個高可用的分布式數據管理與協調框架。基于對ZAB算法的實現,該框架能夠很好地保證分布式環境中數據的一致性。
隨著近年來互聯網系統規模的不斷擴大,大數據時代飛速到來,越來越多的分布式系統將Zookeeper作為核心組件使用,如Hadoop、HBase和Kafka等。
1.數據發布/訂閱
數據發布/訂閱(Publish/Subscribe)系統,即所謂的配置中心,顧名思義就是發布者將數據發布到ZooKeeper的一個或一系列節點上,供訂閱者進行數據訂閱,從而達到動態獲取數據的目的,實現配置信息的集中式管理和數據的動態更新。
在ZooKeeper中,客戶端向服務端注冊自己需要關注的節點,一旦該節點的數據發生變更,那么服務端就會向相應的客戶端發送Watcher事件通知,客戶端接收到這個消息通知之后,需要主動到服務端獲取更新的數據。
我們以一個“數據庫切換”的應用場景展開,看看如何使用ZooKeeper來實現配置管理。
配置存儲
在進行配置管理之前,首先我們需要將初始化配置存儲到ZooKeeper上去。一般情況下,我們可以在ZooKeeper上選取一個數據節點用于配置的存儲,例如/app1/database_config
我們將需要集中管理的配置信息寫入該數據節點中,例如:
mysql.url=localhost:3306 mysql.username=root mysql.password=root配置獲取
集群中每臺機器在啟動初始化階段,首先會從上面提到的ZooKeeper配置節點上讀取數據庫信息,同時,客戶端還需要在該配置節點上注冊一個數據變更的Watcher監聽,一旦發生節點數據變更,所有訂閱的客戶端都能夠后去到數據變更通知。
配置變更
在系統運行過程中,可能會出現需要進行數據庫切換的情況,這個時候就需要進行配置變更。我們只需要對ZooKeeper上配置節點的內容進行更新,ZooKeeper就能幫我們將數據變更的通知發送到各個客戶端。
2.命名服務
ZooKeeper的命名服務功能主要是根據指定名字來獲取資源或服務的地址,提供者等信息,利用其znode的特點和watcher機制,將其作為動態注冊和獲取服務信息的配置中心,統一管理服務名稱和其對應的服務器列表信息,我們能夠近乎實時地感知到后端服務器的狀態(上線、下線、宕機)。
例如,在Dubbo中使用ZooKeeper來作為其命名服務,維護全局的服務地址列表。在Dubbo實現中:
服務提供者在啟動的時候,向ZooKeeper上的指定節點/dubbo/${serviceName}/providers目錄下寫入自己的URL地址,這個操作就完成了服務的發布。
服務消費者啟動的時候,訂閱/dubbo/{serviceName}/providers目錄下的提供者URL地址, 并向/dubbo/{serviceName} /consumers目錄下寫入自己的URL地址。
命名服務的作用
-
負載均衡
輪詢服務注冊表,盡可能將服務請求均勻分配到所有注冊有效的服務器上。
-
健康檢查
動態維護服務地址注冊表,利用心跳請求實時監控注冊服務狀態,刪除無效服務節點,維護有效的地址注冊表。
-
調用監控
通過統計注冊表各個子節點被訪問次數來監控服務調用情況。
-
動態路由
可以通過配置注冊表參數,在不修改服務代碼的情況下,動態指定服務訪問的機器。
-
動態配置
注冊表的子節點可以作為單服務器的配置中心,可以直接修改節點配置而不是修改代碼的方式,動態修改服務運行的部分參數。
3.集群管理
ZooKeeper具有以下兩大特性:
-
客戶端如果對ZooKeeper的一個數據節點注冊Watcher監聽,那么當數據節點的內容或是其子節點列表發送變更時,ZooKeeper服務器就會向訂閱的客戶端發送變更通知
-
對在ZooKeeper上創建的臨時節點,一旦客戶端與服務器之間的會話失效,那么該臨時節點也被自動清除
利用ZooKeeper的這兩大特性,就可以實現另一種集群機器存活性監控的系統。例如:監控系統在/clusterServers節點上注冊一個Watcher監聽,那么但凡進行動態添加機器的操作,都會在該節點下創建一個臨時節點:/clusterServers/[HostName]。這樣一來,監控系統就能夠實時監測到機器的變動情況。
下面用一個典型例子來看看如何實現集群管理。
在線云主機管理
在線云主機管理通常出現在那些虛擬主機提供商的應用場景中。在這類集群管理中,有很重要的一塊就是集群機器的監控。這個場景通常對于集群中的機器狀態,尤其是機器在線率的統計有較高的要求,同時需要能夠快速地對集群中機器的變更做出相應。
在傳統的實現方案中,監控系統通過某種方案(比如檢測主機的指定端口)來對每臺機器進行定時檢測,或者每臺機器自己定時向監控系統匯報。但是這種方式需要每一個業務系統的開發人員自己來處理網絡通信、協議涉及、調度和容災等諸多問題。
下面我們看看ZooKeeper怎么實現。
機器上/下線
在新增機器的時候,首先將制定的Agent部署到這些機器上去,啟動之后,首先向ZooKeeper的指定節點進行注冊。具體的做法就是在機器列表節點下面創建一個臨時子節點,如下圖:
?
當Agent在ZooKeeper上創建完這個臨時子節點后,關注/XAE/machines節點的監控中心就會接收到“子節點變更”事件,即上線通知,于是就可以對這個新加入的機器開啟響應的后臺管理邏輯。機器下線也是同理。
機器監控
對于一個在線云主機系統,不僅要對機器的在線狀態進行檢測,還需要對機器的運行時狀態進行監控。在運行的過程中,Agent會定時將主機的運行狀態信息寫入ZooKeeper的主機節點,監控中心通過訂閱這些節點的數據變更通知來間接獲取主機的運行時信息。
4.Master選舉
Master選舉是一個在分布式系統中非常常見的應用場景。在分布式系統中,Master往往用來協調集群中其它系統單元,具有對分布式系統狀態變更的決定權。例如,在一些讀寫分離的應用場景中,客戶端的寫請求往往是由Master來處理的;而在另一些場景中,Master則常常負責處理一些復雜的邏輯,并將處理結果同步給集群中其它系統單元。
在分布式環境中,經常會碰到這樣的應用場景:集群中的所有系統單元需要對前端業務提供數據,比如一個商品id,而這些數據往往需要從一系列的海量數據處理中計算得到-這通常是一個非常耗費IO和CPU資源的過程。鑒于該計算的復雜性,如果讓集群中的所有機器都執行這個計算邏輯的話,會耗費非常多的資源。一種比較好的方法就是只讓集群中的部分,或者一臺機器去處理,處理完成,共享給集群中的其它客戶端機器。
這里我們以一個簡單的廣告投放系統來講解。
圖中的Client集群每天會定時通過ZooKeeper來實現Master選舉。選舉產生Master后,這個Master就會負責進行一系列的海量數據處理,最終計算得到一個結果。同時,Master通知其他客戶端獲取這個結果。
ZooKeeper有一個全局唯一性,即ZooKeeper將會保證客戶端無法重復創建一個已經存在的數據節點。也就是說,如果同時有多個客戶端請求創建同一個節點,那么最終只有一個客戶端能創建成功。
比如,我們在ZooKeeper上創建一個日期節點
客戶端每天定時往ZooKeeper上創建一個臨時節點,在這個過程中,只有一個客戶端能夠成功創建這個節點,該客戶端成為Master。同時,其它節點在該節點上注冊一個子節點變更的Watcher,用于監控當前的Master機器是否存過,一旦發現掛了,其余客戶端重新進行選舉。
5.分布式鎖
5.1 排他鎖
排他鎖又稱為寫鎖或獨占鎖,是一種基本的鎖類型。如果事務T對數據對象O加入了排他鎖,那么在整個加鎖期間,只允許事務T對O進行讀取和更新操作,其它任何事務都不能對這個對象進行任何操作-知道T釋放了排他鎖。
下面說下ZooKeeper的實現:
定義鎖
ZooKeeper通過數據節點來表示一個鎖,例如/exclusive_lock/lock節點被定義為一個鎖。
獲取鎖
在需要獲取排他鎖時,所有的客戶端都會試圖通過調用create()接口,在/exclusive_lock節點下創建臨時子節點/exclusive_lock/lock。創建成功的客戶端可以認為獲取了鎖。其它創建失敗的開啟Watcher監聽,實時監聽lock節點的變更情況。
釋放鎖
節點是一個臨時節點,在以下兩種情況下,都有可能釋放鎖。
-
正常獲取鎖的客戶端機器宕機,那么該臨時節點就會被移除
-
正常執行完業務邏輯,客戶端會主動將自己創建的臨時節點刪除
整個流程如下:
5.2 共享鎖
共享鎖又稱為讀鎖,同樣是一種基本的鎖類型。如果事務T對數據對象O加入了共享鎖,那么當前對象只能對O進行讀取操作,其它事務也只能對這個數據對象加共享鎖---直到該數據對象上的所有共享鎖都被釋放。
共享鎖和排他鎖最根本的區別在于,加入排他鎖后,數據對象只對一個事務可見,而加上共享鎖后,數據對所有事務都可見。
定義鎖
和排他鎖一樣,同樣是通過ZooKeeper上的數據節點來表示一個鎖,是一個類似于/shared_lock/[Hostname]-請求類型-序號的臨時順序節點。
獲取鎖
在需要獲取共享鎖時,客戶端會在/shared_lock這個節點下面創建一個臨時順序節點,如果是讀請求,就創建例如/shared_lock/192.168.0.1-R-0000000001的節點;如果是寫請求,就創建例如/shared_lock/192.168.0.1-W-0000000001的節點
判斷讀寫順序
根據共享鎖的定義,不同的事務都可以同時對同一個數據對象進行讀取操作,而更新操作必須在當前沒有任何事務進行讀寫操作的情況下進行。
ZooKeeper確定讀寫順序大致為以下四個步驟:
1.創建完節點后,獲取/shared_lock節點下的所有子節點,并對該節點注冊子節點變更的Watcher監聽
2.確定自己的節點序號在所有子節點中的順序
3.讀請求和寫請求兩種情況:
-
對于讀請求:
如果沒有比自己序號小的子節點,或是所有比自己序號小的子節點都是讀請求,那么就表明自己獲取到了共享鎖;如果比自己序號小的子節點中有寫請求,就進入等待。
-
對于寫請求:
如果自己不是序號最小的子節點,那么就需要進入等待。
4.接受到Watcher通知后,重復步驟1。
釋放鎖
釋放鎖的邏輯和排他鎖是一樣的。
?
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的ZooKeeper的典型应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka在Spring项目中的实战演练
- 下一篇: Kafka在ZooKeeper中的应用