日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转】ZooKeeper原理及使用

發(fā)布時間:2025/3/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】ZooKeeper原理及使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文鏈接? http://www.wuzesheng.com/?p=2609

?

ZooKeeper是Hadoop Ecosystem中非常重要的組件,它的主要功能是為分布式系統(tǒng)提供一致性協(xié)調(Coordination)服務,與之對應的Google的類似服務叫Chubby。今天這篇文章分為三個部分來介紹ZooKeeper,第一部分介紹ZooKeeper的基本原理,第二部分介紹ZooKeeper提供的Client API的使用,第三部分介紹一些ZooKeeper典型的應用場景。

ZooKeeper基本原理

1. 數(shù)據(jù)模型 如上圖所示,ZooKeeper數(shù)據(jù)模型的結構與Unix文件系統(tǒng)很類似,整體上可以看作是一棵樹,每個節(jié)點稱做一個ZNode。每個ZNode都可以通過其路徑唯一標識,比如上圖中第三層的第一個ZNode, 它的路徑是/app1/c1。在每個ZNode上可存儲少量數(shù)據(jù)(默認是1M, 可以通過配置修改, 通常不建議在ZNode上存儲大量的數(shù)據(jù)),這個特性非常有用,在后面的典型應用場景中會介紹到。另外,每個ZNode上還存儲了其Acl信息,這里需要注意,雖說ZNode的樹形結構跟Unix文件系統(tǒng)很類似,但是其Acl與Unix文件系統(tǒng)是完全不同的,每個ZNode的Acl的獨立的,子結點不會繼承父結點的,關于ZooKeeper中的Acl可以參考之前寫過的一篇文章《說說Zookeeper中的ACL》。

2.重要概念? 2.1 ZNode 前文已介紹了ZNode, ZNode根據(jù)其本身的特性,可以分為下面兩類:

  • Regular ZNode: 常規(guī)型ZNode, 用戶需要顯式的創(chuàng)建、刪除
  • Ephemeral ZNode: 臨時型ZNode, 用戶創(chuàng)建它之后,可以顯式的刪除,也可以在創(chuàng)建它的Session結束后,由ZooKeeper Server自動刪除

ZNode還有一個Sequential的特性,如果創(chuàng)建的時候指定的話,該ZNode的名字后面會自動Append一個不斷增加的SequenceNo。

2.2 Session Client與ZooKeeper之間的通信,需要創(chuàng)建一個Session,這個Session會有一個超時時間。因為ZooKeeper集群會把Client的Session信息持久化,所以在Session沒超時之前,Client與ZooKeeper Server的連接可以在各個ZooKeeper Server之間透明地移動。

在實際的應用中,如果Client與Server之間的通信足夠頻繁,Session的維護就不需要其它額外的消息了。否則,ZooKeeper Client會每t/3 ms發(fā)一次心跳給Server,如果Client 2t/3 ms沒收到來自Server的心跳回應,就會換到一個新的ZooKeeper Server上。這里t是用戶配置的Session的超時時間。

2.3 Watcher ZooKeeper支持一種Watch操作,Client可以在某個ZNode上設置一個Watcher,來Watch該ZNode上的變化。如果該ZNode上有相應的變化,就會觸發(fā)這個Watcher,把相應的事件通知給設置Watcher的Client。需要注意的是,ZooKeeper中的Watcher是一次性的,即觸發(fā)一次就會被取消,如果想繼續(xù)Watch的話,需要客戶端重新設置Watcher。這個跟epoll里的oneshot模式有點類似。

3. ZooKeeper特性? 3.1 讀、寫(更新)模式 在ZooKeeper集群中,讀可以從任意一個ZooKeeper Server讀,這一點是保證ZooKeeper比較好的讀性能的關鍵;寫的請求會先Forwarder到Leader,然后由Leader來通過ZooKeeper中的原子廣播協(xié)議,將請求廣播給所有的Follower,Leader收到一半以上的寫成功的Ack后,就認為該寫成功了,就會將該寫進行持久化,并告訴客戶端寫成功了。

3.2 WAL和Snapshot 和大多數(shù)分布式系統(tǒng)一樣,ZooKeeper也有WAL(Write-Ahead-Log),對于每一個更新操作,ZooKeeper都會先寫WAL, 然后再對內存中的數(shù)據(jù)做更新,然后向Client通知更新結果。另外,ZooKeeper還會定期將內存中的目錄樹進行Snapshot,落地到磁盤上,這個跟HDFS中的FSImage是比較類似的。這么做的主要目的,一當然是數(shù)據(jù)的持久化,二是加快重啟之后的恢復速度,如果全部通過Replay WAL的形式恢復的話,會比較慢。

3.3 FIFO 對于每一個ZooKeeper客戶端而言,所有的操作都是遵循FIFO順序的,這一特性是由下面兩個基本特性來保證的:一是ZooKeeper Client與Server之間的網(wǎng)絡通信是基于TCP,TCP保證了Client/Server之間傳輸包的順序;二是ZooKeeper Server執(zhí)行客戶端請求也是嚴格按照FIFO順序的。

3.4 Linearizability 在ZooKeeper中,所有的更新操作都有嚴格的偏序關系,更新操作都是串行執(zhí)行的,這一點是保證ZooKeeper功能正確性的關鍵。

ZooKeeper Client API

ZooKeeper Client Library提供了豐富直觀的API供用戶程序使用,下面是一些常用的API:

  • create(path, data, flags): 創(chuàng)建一個ZNode, path是其路徑,data是要存儲在該ZNode上的數(shù)據(jù),flags常用的有: PERSISTEN, PERSISTENT_SEQUENTAIL, EPHEMERAL, EPHEMERAL_SEQUENTAIL
  • delete(path, version): 刪除一個ZNode,可以通過version刪除指定的版本, 如果version是-1的話,表示刪除所有的版本
  • exists(path, watch): 判斷指定ZNode是否存在,并設置是否Watch這個ZNode。這里如果要設置Watcher的話,Watcher是在創(chuàng)建ZooKeeper實例時指定的,如果要設置特定的Watcher的話,可以調用另一個重載版本的exists(path, watcher)。以下幾個帶watch參數(shù)的API也都類似
  • getData(path, watch): 讀取指定ZNode上的數(shù)據(jù),并設置是否watch這個ZNode
  • setData(path, watch): 更新指定ZNode的數(shù)據(jù),并設置是否Watch這個ZNode
  • getChildren(path, watch): 獲取指定ZNode的所有子ZNode的名字,并設置是否Watch這個ZNode
  • sync(path): 把所有在sync之前的更新操作都進行同步,達到每個請求都在半數(shù)以上的ZooKeeper Server上生效。path參數(shù)目前沒有用
  • setAcl(path, acl): 設置指定ZNode的Acl信息
  • getAcl(path): 獲取指定ZNode的Acl信息

ZooKeeper典型應用場景

1. 名字服務(NameService)? 分布式應用中,通常需要一套完備的命令機制,既能產(chǎn)生唯一的標識,又方便人識別和記憶。 我們知道,每個ZNode都可以由其路徑唯一標識,路徑本身也比較簡潔直觀,另外ZNode上還可以存儲少量數(shù)據(jù),這些都是實現(xiàn)統(tǒng)一的NameService的基礎。下面以在HDFS中實現(xiàn)NameService為例,來說明實現(xiàn)NameService的基本布驟:

  • 目標:通過簡單的名字來訪問指定的HDFS機群
  • 定義命名規(guī)則:這里要做到簡潔易記憶。下面是一種可選的方案: [serviceScheme://][zkCluster]-[clusterName],比如hdfs://lgprc-example/表示基于lgprc ZooKeeper集群的用來做example的HDFS集群
  • 配置DNS映射: 將zkCluster的標識lgprc通過DNS解析到對應的ZooKeeper集群的地址
  • 創(chuàng)建ZNode: 在對應的ZooKeeper上創(chuàng)建/NameService/hdfs/lgprc-example結點,將HDFS的配置文件存儲于該結點下
  • 用戶程序要訪問hdfs://lgprc-example/的HDFS集群,首先通過DNS找到lgprc的ZooKeeper機群的地址,然后在ZooKeeper的/NameService/hdfs/lgprc-example結點中讀取到HDFS的配置,進而根據(jù)得到的配置,得到HDFS的實際訪問入口

2. 配置管理(Configuration Management)? 在分布式系統(tǒng)中,常會遇到這樣的場景: 某個Job的很多個實例在運行,它們在運行時大多數(shù)配置項是相同的,如果想要統(tǒng)一改某個配置,一個個實例去改,是比較低效,也是比較容易出錯的方式。通過ZooKeeper可以很好的解決這樣的問題,下面的基本的步驟:

  • 將公共的配置內容放到ZooKeeper中某個ZNode上,比如/service/common-conf
  • 所有的實例在啟動時都會傳入ZooKeeper集群的入口地址,并且在運行過程中Watch /service/common-conf這個ZNode
  • 如果集群管理員修改了了common-conf,所有的實例都會被通知到,根據(jù)收到的通知更新自己的配置,并繼續(xù)Watch /service/common-conf

3. 組員管理(Group Membership)? 在典型的Master-Slave結構的分布式系統(tǒng)中,Master需要作為“總管”來管理所有的Slave, 當有Slave加入,或者有Slave宕機,Master都需要感知到這個事情,然后作出對應的調整,以便不影響整個集群對外提供服務。以HBase為例,HMaster管理了所有的RegionServer,當有新的RegionServer加入的時候,HMaster需要分配一些Region到該RegionServer上去,讓其提供服務;當有RegionServer宕機時,HMaster需要將該RegionServer之前服務的Region都重新分配到當前正在提供服務的其它RegionServer上,以便不影響客戶端的正常訪問。下面是這種場景下使用ZooKeeper的基本步驟:

  • Master在ZooKeeper上創(chuàng)建/service/slaves結點,并設置對該結點的Watcher
  • 每個Slave在啟動成功后,創(chuàng)建唯一標識自己的臨時性(Ephemeral)結點/service/slaves/${slave_id},并將自己地址(ip/port)等相關信息寫入該結點
  • Master收到有新子結點加入的通知后,做相應的處理
  • 如果有Slave宕機,由于它所對應的結點是臨時性結點,在它的Session超時后,ZooKeeper會自動刪除該結點
  • Master收到有子結點消失的通知,做相應的處理

4. 簡單互斥鎖(Simple Lock)? 我們知識,在傳統(tǒng)的應用程序中,線程、進程的同步,都可以通過操作系統(tǒng)提供的機制來完成。但是在分布式系統(tǒng)中,多個進程之間的同步,操作系統(tǒng)層面就無能為力了。這時候就需要像ZooKeeper這樣的分布式的協(xié)調(Coordination)服務來協(xié)助完成同步,下面是用ZooKeeper實現(xiàn)簡單的互斥鎖的步驟,這個可以和線程間同步的mutex做類比來理解:

  • 多個進程嘗試去在指定的目錄下去創(chuàng)建一個臨時性(Ephemeral)結點 /locks/my_lock
  • ZooKeeper能保證,只會有一個進程成功創(chuàng)建該結點,創(chuàng)建結點成功的進程就是搶到鎖的進程,假設該進程為A
  • 其它進程都對/locks/my_lock進行Watch
  • 當A進程不再需要鎖,可以顯式刪除/locks/my_lock釋放鎖;或者是A進程宕機后Session超時,ZooKeeper系統(tǒng)自動刪除/locks/my_lock結點釋放鎖。此時,其它進程就會收到ZooKeeper的通知,并嘗試去創(chuàng)建/locks/my_lock搶鎖,如此循環(huán)反復

5. 互斥鎖(Simple Lock without Herd Effect)? 上一節(jié)的例子中有一個問題,每次搶鎖都會有大量的進程去競爭,會造成羊群效應(Herd Effect),為了解決這個問題,我們可以通過下面的步驟來改進上述過程:

  • 每個進程都在ZooKeeper上創(chuàng)建一個臨時的順序結點(Ephemeral Sequential) /locks/lock_${seq}
  • ${seq}最小的為當前的持鎖者(${seq}是ZooKeeper生成的Sequenctial Number)
  • 其它進程都對只watch比它次小的進程對應的結點,比如2 watch 1, 3 watch 2, 以此類推
  • 當前持鎖者釋放鎖后,比它次大的進程就會收到ZooKeeper的通知,它成為新的持鎖者,如此循環(huán)反復

這里需要補充一點,通常在分布式系統(tǒng)中用ZooKeeper來做Leader Election(選主)就是通過上面的機制來實現(xiàn)的,這里的持鎖者就是當前的“主”。

6. 讀寫鎖(Read/Write Lock)? 我們知道,讀寫鎖跟互斥鎖相比不同的地方是,它分成了讀和寫兩種模式,多個讀可以并發(fā)執(zhí)行,但寫和讀、寫都互斥,不能同時執(zhí)行行。利用ZooKeeper,在上面的基礎上,稍做修改也可以實現(xiàn)傳統(tǒng)的讀寫鎖的語義,下面是基本的步驟:

  • 每個進程都在ZooKeeper上創(chuàng)建一個臨時的順序結點(Ephemeral Sequential) /locks/lock_${seq}
  • ${seq}最小的一個或多個結點為當前的持鎖者,多個是因為多個讀可以并發(fā)
  • 需要寫鎖的進程,Watch比它次小的進程對應的結點
  • 需要讀鎖的進程,Watch比它小的最后一個寫進程對應的結點
  • 當前結點釋放鎖后,所有Watch該結點的進程都會被通知到,他們成為新的持鎖者,如此循環(huán)反復

7. 屏障(Barrier)? 在分布式系統(tǒng)中,屏障是這樣一種語義: 客戶端需要等待多個進程完成各自的任務,然后才能繼續(xù)往前進行下一步。下用是用ZooKeeper來實現(xiàn)屏障的基本步驟:

  • Client在ZooKeeper上創(chuàng)建屏障結點/barrier/my_barrier,并啟動執(zhí)行各個任務的進程
  • Client通過exist()來Watch /barrier/my_barrier結點
  • 每個任務進程在完成任務后,去檢查是否達到指定的條件,如果沒達到就啥也不做,如果達到了就把/barrier/my_barrier結點刪除
  • Client收到/barrier/my_barrier被刪除的通知,屏障消失,繼續(xù)下一步任務

8. 雙屏障(Double Barrier) 雙屏障是這樣一種語義: 它可以用來同步一個任務的開始和結束,當有足夠多的進程進入屏障后,才開始執(zhí)行任務;當所有的進程都執(zhí)行完各自的任務后,屏障才撤銷。下面是用ZooKeeper來實現(xiàn)雙屏障的基本步驟:

    • 進入屏障:

?

  • Client Watch /barrier/ready結點, 通過判斷該結點是否存在來決定是否啟動任務
  • 每個任務進程進入屏障時創(chuàng)建一個臨時結點/barrier/process/${process_id},然后檢查進入屏障的結點數(shù)是否達到指定的值,如果達到了指定的值,就創(chuàng)建一個/barrier/ready結點,否則繼續(xù)等待
  • Client收到/barrier/ready創(chuàng)建的通知,就啟動任務執(zhí)行過程
    • 離開屏障:

?

  • Client Watch /barrier/process,如果其沒有子結點,就可以認為任務執(zhí)行結束,可以離開屏障

?

  • 每個任務進程執(zhí)行任務結束后,都需要刪除自己對應的結點/barrier/process/${process_id}
轉載地址:http://www.wuzesheng.com/?p=2609
數(shù)據(jù)發(fā)布與訂閱(配置中心)
發(fā)布與訂閱模型,即所謂的配置中心,顧名思義就是發(fā)布者將數(shù)據(jù)發(fā)布到ZK節(jié)點上,供訂閱者動態(tài)獲取數(shù)據(jù),實現(xiàn)配置信息的集中式管理和動態(tài)更新。例如全局的配置信息,服務式服務框架的服務地址列表等就非常適合使用。
  • 應用中用到的一些配置信息放到ZK上進行集中管理。這類場景通常是這樣:應用在啟動的時候會主動來獲取一次配置,同時,在節(jié)點上注冊一個Watcher,這樣一來,以后每次配置有更新的時候,都會實時通知到訂閱的客戶端,從來達到獲取最新配置信息的目的。
  • 分布式搜索服務中,索引的元信息和服務器集群機器的節(jié)點狀態(tài)存放在ZK的一些指定節(jié)點,供各個客戶端訂閱使用。
  • 分布式日志收集系統(tǒng)。這個系統(tǒng)的核心工作是收集分布在不同機器的日志。收集器通常是按照應用來分配收集任務單元,因此需要在ZK上創(chuàng)建一個以應用名作為path的節(jié)點P,并將這個應用的所有機器ip,以子節(jié)點的形式注冊到節(jié)點P上,這樣一來就能夠實現(xiàn)機器變動的時候,能夠實時通知到收集器調整任務分配。
  • 系統(tǒng)中有些信息需要動態(tài)獲取,并且還會存在人工手動去修改這個信息的發(fā)問。通常是暴露出接口,例如JMX接口,來獲取一些運行時的信息。引入ZK之后,就不用自己實現(xiàn)一套方案了,只要將這些信息存放到指定的ZK節(jié)點上即可。

注意:在上面提到的應用場景中,有個默認前提是:數(shù)據(jù)量很小,但是數(shù)據(jù)更新可能會比較快的場景。

負載均衡
這里說的負載均衡是指軟負載均衡。在分布式環(huán)境中,為了保證高可用性,通常同一個應用或同一個服務的提供方都會部署多份,達到對等服務。而消費者就須要在這些對等的服務器中選擇一個來執(zhí)行相關的業(yè)務邏輯,其中比較典型的是消息中間件中的生產(chǎn)者,消費者負載均衡。
消息中間件中發(fā)布者和訂閱者的負載均衡,linkedin開源的KafkaMQ和阿里開源的metaq都是通過zookeeper來做到生產(chǎn)者、消費者的負載均衡。這里以metaq為例如講下: 生產(chǎn)者負載均衡:metaq發(fā)送消息的時候,生產(chǎn)者在發(fā)送消息的時候必須選擇一臺broker上的一個分區(qū)來發(fā)送消息,因此metaq在運行過程中,會把所有broker和對應的分區(qū)信息全部注冊到ZK指定節(jié)點上,默認的策略是一個依次輪詢的過程,生產(chǎn)者在通過ZK獲取分區(qū)列表之后,會按照brokerId和partition的順序排列組織成一個有序的分區(qū)列表,發(fā)送的時候按照從頭到尾循環(huán)往復的方式選擇一個分區(qū)來發(fā)送消息。

?

消費負載均衡:

在消費過程中,一個消費者會消費一個或多個分區(qū)中的消息,但是一個分區(qū)只會由一個消費者來消費。MetaQ的消費策略是:

  • 每個分區(qū)針對同一個group只掛載一個消費者。
  • 如果同一個group的消費者數(shù)目大于分區(qū)數(shù)目,則多出來的消費者將不參與消費。
  • 如果同一個group的消費者數(shù)目小于分區(qū)數(shù)目,則有部分消費者需要額外承擔消費任務。

在某個消費者故障或者重啟等情況下,其他消費者會感知到這一變化(通過 zookeeper watch消費者列表),然后重新進行負載均衡,保證所有的分區(qū)都有消費者進行消費。

命名服務(Naming Service)
命名服務也是分布式系統(tǒng)中比較常見的一類場景。在分布式系統(tǒng)中,通過使用命名服務,客戶端應用能夠根據(jù)指定名字來獲取資源或服務的地址,提供者等信息。被命名的實體通常可以是集群中的機器,提供的服務地址,遠程對象等等——這些我們都可以統(tǒng)稱他們?yōu)槊?#xff08;Name)。其中較為常見的就是一些分布式服務框架中的服務地址列表。通過調用ZK提供的創(chuàng)建節(jié)點的API,能夠很容易創(chuàng)建一個全局唯一的path,這個path就可以作為一個名稱。
阿里巴巴集團開源的分布式服務框架Dubbo中使用ZooKeeper來作為其命名服務,維護全局的服務地址列表,點擊這里查看Dubbo開源項目。在Dubbo實現(xiàn)中:

?

服務提供者在啟動的時候,向ZK上的指定節(jié)點/dubbo/${serviceName}/providers目錄下寫入自己的URL地址,這個操作就完成了服務的發(fā)布。

服務消費者啟動的時候,訂閱/dubbo/${serviceName}/providers目錄下的提供者URL地址, 并向/dubbo/${serviceName} /consumers目錄下寫入自己的URL地址。

注意,所有向ZK上注冊的地址都是臨時節(jié)點,這樣就能夠保證服務提供者和消費者能夠自動感應資源的變化。

另外,Dubbo還有針對服務粒度的監(jiān)控,方法是訂閱/dubbo/${serviceName}目錄下所有提供者和消費者的信息。

分布式通知/協(xié)調
ZooKeeper中特有watcher注冊與異步通知機制,能夠很好的實現(xiàn)分布式環(huán)境下不同系統(tǒng)之間的通知與協(xié)調,實現(xiàn)對數(shù)據(jù)變更的實時處理。使用方法通常是不同系統(tǒng)都對ZK上同一個znode進行注冊,監(jiān)聽znode的變化(包括znode本身內容及子節(jié)點的),其中一個系統(tǒng)update了znode,那么另一個系統(tǒng)能夠收到通知,并作出相應處理
  • 另一種心跳檢測機制:檢測系統(tǒng)和被檢測系統(tǒng)之間并不直接關聯(lián)起來,而是通過zk上某個節(jié)點關聯(lián),大大減少系統(tǒng)耦合。
  • 另一種系統(tǒng)調度模式:某系統(tǒng)有控制臺和推送系統(tǒng)兩部分組成,控制臺的職責是控制推送系統(tǒng)進行相應的推送工作。管理人員在控制臺作的一些操作,實際上是修改了ZK上某些節(jié)點的狀態(tài),而ZK就把這些變化通知給他們注冊Watcher的客戶端,即推送系統(tǒng),于是,作出相應的推送任務。
  • 另一種工作匯報模式:一些類似于任務分發(fā)系統(tǒng),子任務啟動后,到zk來注冊一個臨時節(jié)點,并且定時將自己的進度進行匯報(將進度寫回這個臨時節(jié)點),這樣任務管理者就能夠實時知道任務進度。

總之,使用zookeeper來進行分布式通知和協(xié)調能夠大大降低系統(tǒng)之間的耦合

集群管理與Master選舉
  • 集群機器監(jiān)控:這通常用于那種對集群中機器狀態(tài),機器在線率有較高要求的場景,能夠快速對集群中機器變化作出響應。這樣的場景中,往往有一個監(jiān)控系統(tǒng),實時檢測集群機器是否存活。過去的做法通常是:監(jiān)控系統(tǒng)通過某種手段(比如ping)定時檢測每個機器,或者每個機器自己定時向監(jiān)控系統(tǒng)匯報“我還活著”。 這種做法可行,但是存在兩個比較明顯的問題:
  • 集群中機器有變動的時候,牽連修改的東西比較多。
  • 有一定的延時。
  • 利用ZooKeeper有兩個特性,就可以實時另一種集群機器存活性監(jiān)控系統(tǒng):

  • 客戶端在節(jié)點 x 上注冊一個Watcher,那么如果 x?的子節(jié)點變化了,會通知該客戶端。
  • 創(chuàng)建EPHEMERAL類型的節(jié)點,一旦客戶端和服務器的會話結束或過期,那么該節(jié)點就會消失。
  • 例如,監(jiān)控系統(tǒng)在 /clusterServers 節(jié)點上注冊一個Watcher,以后每動態(tài)加機器,那么就往 /clusterServers 下創(chuàng)建一個 EPHEMERAL類型的節(jié)點:/clusterServers/{hostname}. 這樣,監(jiān)控系統(tǒng)就能夠實時知道機器的增減情況,至于后續(xù)處理就是監(jiān)控系統(tǒng)的業(yè)務了。

    • Master選舉則是zookeeper中最為經(jīng)典的應用場景了。

    在分布式環(huán)境中,相同的業(yè)務應用分布在不同的機器上,有些業(yè)務邏輯(例如一些耗時的計算,網(wǎng)絡I/O處理),往往只需要讓整個集群中的某一臺機器進行執(zhí)行,其余機器可以共享這個結果,這樣可以大大減少重復勞動,提高性能,于是這個master選舉便是這種場景下的碰到的主要問題。

    利用ZooKeeper的強一致性,能夠保證在分布式高并發(fā)情況下節(jié)點創(chuàng)建的全局唯一性,即:同時有多個客戶端請求創(chuàng)建 /currentMaster 節(jié)點,最終一定只有一個客戶端請求能夠創(chuàng)建成功。利用這個特性,就能很輕易的在分布式環(huán)境中進行集群選取了。

    另外,這種場景演化一下,就是動態(tài)Master選舉。這就要用到?EPHEMERAL_SEQUENTIAL類型節(jié)點的特性了。

    上文中提到,所有客戶端創(chuàng)建請求,最終只有一個能夠創(chuàng)建成功。在這里稍微變化下,就是允許所有請求都能夠創(chuàng)建成功,但是得有個創(chuàng)建順序,于是所有的請求最終在ZK上創(chuàng)建結果的一種可能情況是這樣: /currentMaster/{sessionId}-1 ,?/currentMaster/{sessionId}-2 ,?/currentMaster/{sessionId}-3 ….. 每次選取序列號最小的那個機器作為Master,如果這個機器掛了,由于他創(chuàng)建的節(jié)點會馬上小時,那么之后最小的那個機器就是Master了。

    • 在搜索系統(tǒng)中,如果集群中每個機器都生成一份全量索引,不僅耗時,而且不能保證彼此之間索引數(shù)據(jù)一致。因此讓集群中的Master來進行全量索引的生成,然后同步到集群中其它機器。另外,Master選舉的容災措施是,可以隨時進行手動指定master,就是說應用在zk在無法獲取master信息時,可以通過比如http方式,向一個地方獲取master。
    • 在Hbase中,也是使用ZooKeeper來實現(xiàn)動態(tài)HMaster的選舉。在Hbase實現(xiàn)中,會在ZK上存儲一些ROOT表的地址和HMaster的地址,HRegionServer也會把自己以臨時節(jié)點(Ephemeral)的方式注冊到Zookeeper中,使得HMaster可以隨時感知到各個HRegionServer的存活狀態(tài),同時,一旦HMaster出現(xiàn)問題,會重新選舉出一個HMaster來運行,從而避免了HMaster的單點問題
    分布式鎖
    分布式鎖,這個主要得益于ZooKeeper為我們保證了數(shù)據(jù)的強一致性。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序

    ?

    • 所謂保持獨占,就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過create znode的方式來實現(xiàn)。所有客戶端都去創(chuàng)建 /distribute_lock 節(jié)點,最終成功創(chuàng)建的那個客戶端也即擁有了這把鎖。
    • 控制時序,就是所有視圖來獲取這個鎖的客戶端,最終都是會被安排執(zhí)行,只是有個全局時序了。做法和上面基本類似,只是這里 /distribute_lock 已經(jīng)預先存在,客戶端在它下面創(chuàng)建臨時有序節(jié)點(這個可以通過節(jié)點的屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。Zk的父節(jié)點(/distribute_lock)維持一份sequence,保證子節(jié)點創(chuàng)建的時序性,從而也形成了每個客戶端的全局時序。
    分布式隊列
    隊列方面,簡單地講有兩種,一種是常規(guī)的先進先出隊列,另一種是要等到隊列成員聚齊之后的才統(tǒng)一按序執(zhí)行。對于第一種先進先出隊列,和分布式鎖服務中的控制時序場景基本原理一致,這里不再贅述。

    ?

    第二種隊列其實是在FIFO隊列的基礎上作了一個增強。通常可以在 /queue 這個znode下預先建立一個/queue/num 節(jié)點,并且賦值為n(或者直接給/queue賦值n),表示隊列大小,之后每次有隊列成員加入后,就判斷下是否已經(jīng)到達隊列大小,決定是否可以開始執(zhí)行了。這種用法的典型場景是,分布式環(huán)境中,一個大任務Task A,需要在很多子任務完成(或條件就緒)情況下才能進行。這個時候,凡是其中一個子任務完成(就緒),那么就去 /taskList 下建立自己的臨時時序節(jié)點(CreateMode.EPHEMERAL_SEQUENTIAL),當 /taskList 發(fā)現(xiàn)自己下面的子節(jié)點滿足指定個數(shù),就可以進行下一步按序進行處理了。

    ?

    轉載于:https://www.cnblogs.com/ihongyan/p/4703512.html

    總結

    以上是生活随笔為你收集整理的【转】ZooKeeper原理及使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。