圖解ZooKeeper的典型應用場景

zookeeper在不少框架中都有應用,例如:Dubbo,Hadoop,Kafka等,但典型的用法也就幾種,掌握了這幾種用法,再看zookeeper在相關框架中的應用就很輕鬆,下一篇文章將會詳細介紹zookeeper在dubbo中的使用,以便有一個更深入的瞭解node

本文參考了《從Paxos到ZooKeeper》,鑑於本文的定位是一篇科普性質的文章,所以對於一些諸如共享鎖和分佈式隊列的具體實現沒有進行更詳細的描述,實際工做中須要實現時能夠參考這本書redis

zookeeper的數據模型和文件系統相似,每個節點稱爲znode,是zookeeper中的最小數據單元,每個znode上能夠報存數據和掛載子節點,從而構成一個層次化的屬性結構算法

能夠建立以下四種節點(znode)sql

   1.持久節點:節點建立後會一直存在zookeeper服務器上,直到主動刪除數據庫

   2.持久順序節點:每一個節點都會爲它的一級子節點維護一個順序服務器

   3.臨時節點:臨時節點的生命週期和客戶端的會話保持一致。當客戶端會話失效,該節點自動清理數據結構

   4.臨時順序節點:在臨時節點上多了一個順序的特性架構

簡單演示一下經常使用的命令併發

-s : 建立順序節點負載均衡

-e : 建立臨時節點

path : 路徑

data : 數據

acl : 權限

create默認建立的是持久節點

 

執行完上述命令後,數據結構以下所示

這裏簡單說一下順序節點的特性。每次建立順序節點時,zk都會在路徑後面自動添加上10位的數字(計數器),例如 < path >0000000001,< path >0000000002,……這個計數器能夠保證在同一個父節點下是惟一的。在zk內部使用了4個字節的有符號整形來表示這個計數器,也就是說當計數器的大小超過2147483647時,將會發生溢出,每次在父節點下建立一個順序節點時,大小加1,如上圖的3到4

zookeeper提供了分佈式數據發佈/訂閱,容許客戶端向服務端註冊一個watcher監聽,當服務端的一些指定事件觸發了這個watcher,那麼就會向指定客戶端發送一個事件通知來實現分佈式的通知功能。

簡單舉幾個watcher的事件類型

 

基礎知識講解完畢,下面正式分享zookeeper的做用

1.數據發佈/訂閱

數據發佈/訂閱(Publish/Subscribe)系統,即所謂的配置中心,顧明思義就是發佈者將數據發佈到zookeeper的一個或一系列的節點上,供訂閱者進行數據訂閱,進而達到動態獲取數據的目的,實現配置信息的集中式管理和數據的動態更新。

zookeeper採用推拉結合的方式來實現發佈訂閱系統:客戶端向服務端註冊本身須要關注的節點,一旦該節點的數據發生變動,那麼服務端就會向相應的客戶端發送Watcher事件通知,客戶端接收到這個消息通知以後,須要主動到服務端獲取最新的數據。

程序老是須要配置的,若是程序分散部署在多臺機器上,要這個改變配置就變得困難。好吧,如今把這些配置所有放到zookeeper上去,保存在zookeeper的某個目錄節點中,而後全部相關應用程序對這個目錄節點進行監控,一旦配置信息發生變化,每一個應用程序就會收到zookeeper的通知,而後從zookeeper中獲取新的配置信息應用到系統中就好

2.負載均衡

每臺服務端在啓動時都會去zookeeper的servers節點下注冊臨時節點(註冊臨時節點是由於,當服務不可用時,這個臨時節點會消失,客戶端也就不會請求這個服務端),每臺客戶端在啓動時都會去servers節點下取得全部可用的工做服務器列表,並經過必定的負載均衡算法計算得出應該將請求發到哪一個服務器上

3.生成分佈式惟一ID

在過去的單庫單表型系統中,一般可使用數據庫字段自帶的auto_increment屬性來自動爲每條記錄生成一個惟一的ID。可是分庫分表後,就沒法在依靠數據庫的auto_increment屬性來惟一標識一條記錄了。此時咱們就能夠用zookeeper在分佈式環境下生成全局惟一ID。作法以下:每次要生成一個新Id時,建立一個持久順序節點,建立操做返回的節點序號,即爲新Id,而後把比本身節點小的刪除便可。

4.Master選舉

Master選舉是一個在分佈式系統中很是常見的應用場景。在分佈式系統中,Master每每用來協調系統中的其餘系統單元,具備對分佈式系統狀態變動的決定權。例如,在一些讀寫分離的應用場景用,客戶端的寫請求每每是由Master來處理的,而在另外一些場景中, Master則經常負負責處理一下複雜的邏輯,並將處理結果同步給集羣中其餘系統單元。Master選舉能夠說是zookeeper最典型的應用場景了

利用zookeeper的強一致性,可以很好地保證在分佈式高併發狀況下節點的建立必定能保證全局惟一性,即zookeeper將會保證客戶端沒法重複建立一個已經存在的數據節點。也就是說,若是同時有多個客戶端請求建立同一個節點,那麼最終必定只有一個客戶端可以建立成功。利用這個特性,就很容易在分佈式環境中進行Master選舉

客戶端集羣往zookeeper上建立一個/master臨時節點。在這個過程當中,只有一個客戶端可以成功建立這個節點,那麼這個客戶端就成了master。同時其餘沒有在zookeeper上成功建立節點的客戶端,都會在節點/master上註冊一個變動的watcher,用於監控當前的master機器是否存活,一旦發現當前的master掛了,那麼其他的客戶端將會從新進行master選舉

5.分佈式鎖

在同一個JVM中,爲了保證對一個資源的有序訪問,如往文件中寫數據,能夠用synchronized或者ReentrantLock來實現對資源的互斥訪問,若是2個程序在不一樣的JVM中,而且都要往同一個文件中寫數據,如何保證互斥訪問呢?這時就須要用到分佈式鎖了

目前分佈式鎖的主流實現方式有兩種

   1.利用redis setnex(key value) key不存在返回0,key存在返回1

   2.zookeeper實現排他鎖,共享鎖(讀鎖)

這裏只簡單介紹一下排他鎖的實現方式

實現原理和master選舉相似,全部客戶端在/exclusive_lock節點下建立臨時子節點/exclusive_lock/lock,zookeeper會保證在全部的客戶端中,最終只有一個客戶端可以建立成功,那麼就認爲該客戶端獲取了鎖,其餘沒有獲取到鎖的客戶端就須要到/exclusive_lock節點看上註冊一個子節點變動的watcher監聽,以便實時監聽到lock節點的變動狀況

釋放鎖的狀況有以下兩種

   1.當前獲取鎖的客戶端發生宕機,那麼zookeeper上的這個臨時節點就會被刪除

   2.正常執行完業務邏輯後,客戶端會主動將本身建立的臨時節點刪除

整個排他鎖的獲取和釋放流程能夠用以下圖表示

6.分佈式隊列

以下圖,建立/queue做爲一個隊列,而後每建立一個順序節點,視爲一條消息(節點存儲的數據即爲消息內容),生產者每次建立一個新節點,作爲消息發送,消費者監聽queue的子節點變化(或定時輪詢),每次取最小節點當作消費消息,處理完後,刪除該節點。至關於實現了一個FIFO(先進先出)的隊列。注:zookeeper強調的是CP(一致性),而非專爲高併發、高性能場景設計的,若是在高併發,qps很高的狀況下,分佈式隊列需酌情考慮。

歡迎工做一到五年的Java工程師朋友們加入Java填坑之路:860113  481 羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!  

相關文章
相關標籤/搜索