ZooKeeper應用場景及方案介紹

本文主要從應用的角度對ZooKeeper做了淺析,試圖闡明ZooKeeper是什么、主要應用場景有哪些、常用場景可以怎么設計,由于篇幅原因暫未寫ZooKeeper自身設計及一致性方案的實現(xiàn)等,歡迎大家共同探討、對有誤之處進行指正。

ZooKeeper介紹

ZooKeeper是一個開源的分布式協(xié)調服務,由雅虎創(chuàng)建,是Google Chubby的開源實現(xiàn),設計目標是將復雜且易出錯的分布式一致性服務封裝成高效可靠的原語集,以一系列簡單易用的接口提供給用戶使用。ZooKeeper同時是一個典型的分布式數(shù)據(jù)一致性解決方案,致力于提供一個高性能、高可用并且具有嚴格寫順序的分布式協(xié)調服務,分布式應用可以基于它實現(xiàn)如數(shù)據(jù)發(fā)布/訂閱、負載均衡、命名服務、分布式協(xié)調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等功能,官方經典概述點這里。

為什么選擇ZooKeeper?

隨著分布式架構的出現(xiàn),很多分布式應用會遇到數(shù)據(jù)一致性問題,在解決該問題上ZooKeeper是唯一一個成熟穩(wěn)定且被大規(guī)模應用的解決方案。ZooKeeper無論從穩(wěn)定性、性能及易用性上來說都達到了一個工業(yè)級產品的標準。在工程實踐中ZooKeeper(以下簡稱ZK)已經作為核心組件被廣泛應用在很多大型分布式系統(tǒng)中,包括Hadoop、Hbase、Storm、Kafka、Dubbo等。

從應用程序的角度看ZooKeeper

那從分布式應用的角度看ZK能看到一幅怎樣的視圖?一棵樹。這里所說的樹是一個共享的、樹形結構的名字空間,應用可以通過api在這個命名空間中創(chuàng)建組織結構為樹形的數(shù)據(jù)節(jié)點,并且這個空間下的各應用程序看到的視圖是一致的。應用可以通過ZK客戶端連接到服務端(通常是是機器數(shù)量為奇數(shù)的集群),同時會建立相應的會話。

上述節(jié)點對應于ZK服務器內存中一系列被為ZNode的數(shù)據(jù)節(jié)點,而ZNode之間的層級關系就像文件系統(tǒng)的目錄結構一樣,但和傳統(tǒng)的磁盤文件系統(tǒng)不同的是全量數(shù)據(jù)都存儲在內存中,以此來實現(xiàn)提高服務器吞吐、減少延遲的目的,從這一點來說應用只應該存儲控制信息和配置信息到ZNode,而不應該用它來存儲大量數(shù)據(jù)。

數(shù)據(jù)節(jié)點ZNode

在ZK中“節(jié)點”分為兩類,第一類同樣是指構成zk集群的機器,稱之為機器節(jié)點;第二類則是指數(shù)據(jù)模型中的數(shù)據(jù)節(jié)點ZNode。ZK將所有數(shù)據(jù)存儲于內存中,數(shù)據(jù)模型是一顆ZNode Tree,由斜杠分隔的的路徑就是一個ZNode,如/app1/p_1,每個ZNode上都會保存數(shù)據(jù)內容,還會保存相應屬性信息。

ZNode可以分為持久節(jié)點和臨時節(jié)點兩類。持久節(jié)點是指一旦該ZNode被創(chuàng)建了,除非主動進行刪除操作,這個節(jié)點就會一直存在;而臨時節(jié)點的生命周期會和客戶端會話綁定在一起,一旦客戶端會話失效其所創(chuàng)建的所有臨時節(jié)點都會被刪除。

ZK還支持客戶端創(chuàng)建節(jié)點時指定一個特殊的SEQUENTIAL屬性,這個節(jié)點被創(chuàng)建的時候ZK會自動在其節(jié)點名后面追加上一個整形數(shù)字,該數(shù)字是一個由服務端維護的自增數(shù)字,以此實現(xiàn)創(chuàng)建名稱自增的順序節(jié)點。

監(jiān)聽器Watcher

Watcher是ZK中很重要的特性,ZK允許用戶在指定節(jié)點上注冊一些Watcher,在該節(jié)點相關特定事件(比如節(jié)點添加、刪除、子節(jié)點變更等)發(fā)生時Watcher會監(jiān)聽到,ZK服務端會將事件通知到感興趣的客戶端上去,該機制是ZK實現(xiàn)分布式協(xié)調服務的重要特性。

通知的時候服務端只會告訴客戶端一個簡單的事件(通知狀態(tài)、事件類型、節(jié)點路徑)而不包含具體的變化信息(如原始數(shù)據(jù)及變更后的數(shù)據(jù)),客戶端如要具體信息再次主動去重新獲取數(shù)據(jù);此外,無論是服務端還是客戶端,只要Watcher被觸發(fā)ZK就會將其刪除,因此在Watcher的使用上需要反復注冊,這樣輕量的設計有效減輕了服務端壓力,如果Watcher一直有效,節(jié)點更新頻繁時服務端會不斷向客戶端發(fā)送通知,對網(wǎng)絡及服務端性能影響會非常大。

典型應用場景

數(shù)據(jù)發(fā)布/訂閱(以Dubbo注冊中心為例)

Dubbo是集團開源的分布式服務框架,致力于提供高性能和透明化的遠程服務調用解決方案和基于服務框架展開的完整SOA服務治理方案。

其中服務自動發(fā)現(xiàn)是最核心的模塊之一,該模塊提供基于注冊中心的目錄服務,使服務消費方能夠動態(tài)的查找服務提供方,讓服務地址透明化,同時服務提供方可以平滑的對機器進行擴容和縮容,其注冊中心可以基于提供的外部接口來實現(xiàn)各種不同類型的注冊中心,例如數(shù)據(jù)庫、ZK和Redis等。接下來看一下基于ZK實現(xiàn)的Dubbo注冊中心。

/dubbo: 這是Dubbo在ZK上創(chuàng)建的根節(jié)點。

/dubbo/com.foo.BarService: 這是服務節(jié)點,代表了Dubbo的一個服務。

/dubbo/com.foo.BarService/Providers: 這是服務提供者的根節(jié)點,其子節(jié)點代表了每個服務的真正提供者。

/dubbo/com.foo.BarService/Consumers: 這是服務消費者的根節(jié)點,其子節(jié)點代表了沒一個服務的真正消費者

Dubbo基于ZK實現(xiàn)注冊中心的工作流程:

服務提供者:在初始化啟動的時候首先在/dubbo/com.foo.BarService/Providers節(jié)點下創(chuàng)建一個子節(jié)點,同時寫入自己的url地址,代表這個服務的一個提供者。

服務消費者:在啟動的時候讀取并訂閱ZooKeeper上/dubbo/com.foo.BarService/Providersz節(jié)點下的所有子節(jié)點,并解析所有提供者的url地址類作為該服務的地址列表,開始發(fā)起正常調用。同時在Consumers節(jié)點下創(chuàng)建一個臨時節(jié)點,寫入自己的url地址,代表自己是BarService的一個消費者

監(jiān)控中心:監(jiān)控中心是Dubbo服務治理體系的重要一部分,它需要知道一個服務的所有提供者和訂閱者及變化情況。監(jiān)控中心在啟動的時候會通過ZK的/dubbo/com.foo.BarService節(jié)點來獲取所有提供者和消費者的url地址,并注冊Watcher來監(jiān)聽其子節(jié)點變化情況。

所有服務提供者在ZK上創(chuàng)建的節(jié)點都是臨時節(jié)點,利用的是臨時節(jié)點的生命周期和客戶端會話綁定的特性,一旦提供者機器掛掉無法對外提供服務時該臨時節(jié)點就會從ZK上摘除,這樣服務消費者和監(jiān)控中心都能感知到服務提供者的變化。

命名服務

命名服務也是分布式系統(tǒng)中比較常見的一類場景,被命名的實體通??梢允羌褐械臋C器、提供的服務地址或遠程對象,其中較為常見的是一些分布式服務框架中的服務地址列表,通過使用命名服務客戶端應用能夠制定名字來獲取資源的實體、服務地址和提供者的信息等。

上層應用使用命名服務時可能僅需要一個全局唯一的名字,類似于數(shù)據(jù)庫中的唯一主鍵,用數(shù)據(jù)庫自增id是可以的,但分庫分表的情況下就無法依靠數(shù)據(jù)庫的自增屬性來唯一標識一條記錄了。另外UUID也是一種廣泛應用的ID實現(xiàn)方式,但如果是用UUID對服務進行命名的話就太不直觀了,從字面意思根本看不出其表達的含義。下面看下用ZK如何實現(xiàn)全局唯一ID的生成。

之前在ZNode介紹時提過,創(chuàng)建節(jié)點時可以設定為SEQUENTIAL順序節(jié)點,創(chuàng)建后API會返回這個節(jié)點的完整名字,利用這個特性我們就可以來生成全局唯一ID了。

所有客戶端根據(jù)自己的任務類型,在指定類型的任務下創(chuàng)建一個順序節(jié)點,例如“Job-”節(jié)點

節(jié)點創(chuàng)建完畢后會返回一個完整的節(jié)點名稱,如Job-0000000001

客戶端拿到這個返回值后拼接上type類型,例如type1-Job-000000001,這樣就可以作為一個全局唯一的ID了

在ZK中每個數(shù)據(jù)節(jié)點都能維護一份子節(jié)點的順序序列,當客戶端對其創(chuàng)建一個順序子節(jié)點時ZK會自動以后綴的形式在其子節(jié)點上添加一個序號,該場景就利用了ZK的這個特性。

Master選舉

Master選舉是一個在分布式系統(tǒng)中常見的應用場景。分布式系統(tǒng)中Master是一個往往用來協(xié)調集群中其他角色、處理寫操作及復雜邏輯、數(shù)據(jù)同步等,通常決定對分布式系統(tǒng)狀態(tài)變更。針對Master選舉的需求,我們通??梢允褂靡揽筷P系數(shù)據(jù)庫的主鍵特性在集群中選舉出唯一的Master,但是如果當前的Master掛了slave收不到通知怎么辦?顯然關系數(shù)據(jù)庫做不到通知這一點。

ZK創(chuàng)建節(jié)點時有一個重要的特性,利用ZK的強一致性能夠很好的保證在分布式高并發(fā)情況下節(jié)點的創(chuàng)建一定能夠保證全局唯一,即ZK會保證客戶端無法重復創(chuàng)建一個已經存在的數(shù)據(jù)節(jié)點。也就是說同時有多個客戶端請求創(chuàng)建同一個節(jié)點最終一定只有一個客戶端能夠請求創(chuàng)建成功,利用這個特性就能很容易的在分布式環(huán)境中進行Master選舉了。

進行Master選舉時客戶端啟動后可以向ZK請求創(chuàng)建一個臨時節(jié)點,例如/master_election/master。在多個客戶端創(chuàng)建時只有一個能創(chuàng)建成功,那么這個創(chuàng)建成功的客戶端所在的機器就成為了Master。同時其他沒有創(chuàng)建成功的客戶端都可以在節(jié)點/master_election上注冊一個子節(jié)點變更的Watcher來監(jiān)控當前Master是否在線,一旦發(fā)現(xiàn)Master掛了臨時節(jié)點會被刪除,其它客戶端會收到通知,開始重新進行Master選舉。

因此,如果只要求靜態(tài)Maser選舉的話,可以選擇關系數(shù)據(jù)庫;如果需要動態(tài)Master選舉實現(xiàn)HA的話,ZK是更好的選擇。

分布式鎖

分布式鎖是控制分布式系統(tǒng)之間同步訪問共享資源的一種方式。如果不同系統(tǒng)或同一系統(tǒng)不同機器之間共享了同一資源,那訪問這些資源時通常需要一些互斥手段來保證一致性,這種情況下就需要用到分布式鎖了。

使用關系型數(shù)據(jù)庫是一種簡單、廣泛的實現(xiàn)方案,但大多數(shù)大型分布式系統(tǒng)中數(shù)據(jù)庫已經是性能瓶頸了,如果再給數(shù)據(jù)庫添加額外的鎖會更加不堪重負;另外,使用數(shù)據(jù)庫做分布式鎖,當搶到鎖的機器掛掉的話如何釋放鎖也是個頭疼的問題。

接下來看下使用ZK如何實現(xiàn)排他鎖。排他鎖的核心是如何保證當前有且只有一個事務獲得鎖,并且鎖被釋放后所有等待獲取鎖的事務能夠被通知到。

和Master選舉類似,在需要獲取排他鎖時,所有客戶端都會試圖在/exclusive_lock下創(chuàng)建臨時子節(jié)點/exclusive_lock/lock,最終只有一個客戶端能創(chuàng)建成功,該客戶端就獲取到了鎖。同時沒有獲取到鎖的客戶端需要到/exclusive_lock節(jié)點上注冊一個子節(jié)點變更的Watcher監(jiān)聽,用于實時監(jiān)聽lock節(jié)點的變更情況。

/exclusive_lock/lock是一個臨時節(jié)點,在一下兩種情況下都有可能釋放鎖:

當獲取鎖的客戶端掛掉,ZK上的該節(jié)點會被刪除

正常執(zhí)行完業(yè)務邏輯之后客戶端會主動將自己創(chuàng)建的臨時節(jié)點刪除。

無論在什么情況下刪除了lock臨時節(jié)點ZK都會通知在/exclusive_lock節(jié)點上注冊了子節(jié)點變更Watcher監(jiān)聽的客戶端,重新發(fā)起鎖的獲取。

分布式屏障

分布式屏障,舉個栗子,在大規(guī)模分布式并行計算的場景下,最終的合并計算需要基于很多并行計算的子結果來進行,即系統(tǒng)需要滿足特定的條件,一個隊列的元素必須都聚齊之后才能進行后續(xù)處理,否則一直等待。看下如何用ZK來支持這種場景。

開始時/queue_barrier是一個存在的節(jié)點,數(shù)據(jù)內容賦值為一個數(shù)字n來代表滿足條件的機器總數(shù),例如n=10表示只有當/queue_barrier節(jié)點下的子節(jié)點數(shù)量達到10后才會打開屏障繼續(xù)處理。然后所有的客戶端都會到/queue_barrier節(jié)點下創(chuàng)建一個臨時節(jié)點,如/queue_barrier/192.168.0.1。創(chuàng)建完節(jié)點之后根據(jù)以下步驟來確定執(zhí)行順序

調用獲取節(jié)點數(shù)據(jù)的api獲取/queue_barrier節(jié)點的內容:10

調用獲取子節(jié)點總數(shù)的api獲取/queue_barrier下的所有子節(jié)點,并且注冊對子節(jié)點變更的Watcher監(jiān)聽

統(tǒng)計子節(jié)點個數(shù)

如果子節(jié)點個數(shù)小于10則繼續(xù)等待,否則打開屏障繼續(xù)處理

接收到Watcher通知后,重復步驟2

其它常用場景還包括集群管理及分布式隊列等,相信大家都已經有方案了,這里就不再敘述。

ZK在其它大型分布式系統(tǒng)中的應用簡介

在Hadoop中ZooKeeper主要用于實現(xiàn)HA做主備切換(類似上面講的Master選舉),同時在YARN中又特別提供了ZK來存儲應用的運行狀態(tài)。

Kafaka是由LinkedIn開源的分布式消息系統(tǒng),是一個吞吐量極高的分布式消息系統(tǒng),主要用于實現(xiàn)低延遲的發(fā)送和收集大量的事件和日志等活躍數(shù)據(jù)。Kafaka使用ZK作為其分布式協(xié)調框架,將消息生產、消息存儲和消息消費的過程結合起來,保持包括生產者消費者和Broker在內的所有組件無狀態(tài)的情況下,建立起生產者和消費者之間的訂閱關系,并實現(xiàn)生產者和消費者之間的負載均衡。

HBase全稱Hadoop DataBase,是一個基于Hadoop文件系統(tǒng)設計、面向海量數(shù)據(jù)的高可靠性、高性能、面向列、可伸縮的分布式存儲系統(tǒng)。在HBase向在線分布式存儲方向發(fā)展過程中,開發(fā)者發(fā)現(xiàn)如果有RegionServer服務器掛掉時系統(tǒng)和客戶端都無法及時得知信息,服務難以快速遷移到其它RegionServer服務器上,問題原因是缺少相應的分布式協(xié)調組件,于是后來ZooKeeper被加入到HBase的技術體系中。

目前ZooKeeper已經成為HBase的核心組件,應用場景包括系統(tǒng)容錯、RootRegion管理、Region狀態(tài)管理、分布式SplitLog任務管理和Replication管理,除此之外還包括HMaster選舉、Table的enable/disable狀態(tài)記錄及幾乎所有元數(shù)據(jù)的存儲等。Hbase中所有對ZK的操作都封裝在了org.apache.hadoop.hbase.zookeeper這個包中,感興趣可自行研究。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1 Zookeeper概述# ZooKeeper是一個為分布式應用所設計的分布的、開源的協(xié)調服務,它主要是用來解決...
    七寸知架構閱讀 7,489評論 0 101
  • ZooKeeper是一個高可用的分布式數(shù)據(jù)管理與系統(tǒng)協(xié)調框架?;趯axos算法的實現(xiàn),使該框架保證了分布式環(huán)境...
    Bobby0322閱讀 429評論 0 2
  • 一個真正的寫數(shù)據(jù)流程是怎么樣的?一個真正的讀數(shù)據(jù)流程是怎么樣的?一個真正的同步數(shù)據(jù)流程是怎么樣的?從哪里到哪里?什...
    時待吾閱讀 4,317評論 0 14
  • ZooKeeper是Hadoop Ecosystem中非常重要的組件,它的主要功能是為分布式系統(tǒng)提供一致性協(xié)調(C...
    把愛放下會走更遠閱讀 22,099評論 1 18
  • 【1】 不知何時戀家,但又懼怕回家,心里有一顆柔軟的心在脆弱地邊緣徘徊。 每次看見她,都會覺得她老了一點,黑發(fā)不知...
    云朵默閱讀 1,071評論 6 8

友情鏈接更多精彩內容