圖解ZooKeeper的典型應用場景

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

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

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

可以創建如下四種節點(znode)

   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入門到入墳
鏈接:https://www.jianshu.com/p/b73980edd03b
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章