青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2017年5月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910


專注即時通訊及網(wǎng)游服務端編程
------------------------------------
Openresty 官方模塊
Openresty 標準模塊(Opm)
Openresty 三方模塊
------------------------------------
本博收藏大部分文章為轉載,并在文章開頭給出了原文出處,如有再轉,敬請保留相關信息,這是大家對原創(chuàng)作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 219795
  • 排名 - 117

最新評論

閱讀排行榜

http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/
Zookeeper 分布式服務框架是 Apache Hadoop 的一個子項目,它主要是用來解決分布式應用中經(jīng)常遇到的一些數(shù)據(jù)管理問題,如:統(tǒng)一命名服務、狀態(tài)同步服務、集群管理、分布式應用配置項的管理等。本文將從使用者角度詳細介紹 Zookeeper 的安裝和配置文件中各個配置項的意義,以及分析 Zookeeper 的典型的應用場景(配置文件的管理、集群管理、同步鎖、Leader 選舉、隊列管理等),用 Java 實現(xiàn)它們并給出示例代碼。

安裝和配置詳解

本文介紹的 Zookeeper 是以 3.2.2 這個穩(wěn)定版本為基礎,最新的版本可以通過官網(wǎng)http://hadoop.apache.org/zookeeper/來獲取,Zookeeper 的安裝非常簡單,下面將從單機模式和集群模式兩個方面介紹 Zookeeper 的安裝和配置。

單機模式

單機安裝非常簡單,只要獲取到 Zookeeper 的壓縮包并解壓到某個目錄如:/home/zookeeper-3.2.2 下,Zookeeper 的啟動腳本在 bin 目錄下,Linux 下的啟動腳本是 zkServer.sh,在 3.2.2 這個版本 Zookeeper 沒有提供 windows 下的啟動腳本,所以要想在 windows 下啟動 Zookeeper 要自己手工寫一個,如清單 1 所示:

清單 1. Windows 下 Zookeeper 啟動腳本
 setlocal 
 set ZOOCFGDIR=%~dp0%..\conf 
 set ZOO_LOG_DIR=%~dp0%.. 
 set ZOO_LOG4J_PROP=INFO,CONSOLE 
 set CLASSPATH=%ZOOCFGDIR% 

 set CLASSPATH=%~dp0..\*;%~dp0..\lib\*;%CLASSPATH% 
 set CLASSPATH=%~dp0..\build\classes;%~dp0..\build\lib\*;%CLASSPATH% 
 set ZOOCFG=%ZOOCFGDIR%\zoo.cfg 
 set ZOOMAIN=org.apache.zookeeper.server.ZooKeeperServerMain 
 java "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" 
 -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %* 
 endlocal

在你執(zhí)行啟動腳本之前,還有幾個基本的配置項需要配置一下,Zookeeper 的配置文件在 conf 目錄下,這個目錄下有 zoo_sample.cfg 和 log4j.properties,你需要做的就是將 zoo_sample.cfg 改名為 zoo.cfg,因為 Zookeeper 在啟動時會找這個文件作為默認配置文件。下面詳細介紹一下,這個配置文件中各個配置項的意義。

 tickTime=2000 
 dataDir=D:/devtools/zookeeper-3.2.2/build 
 clientPort=2181
  • tickTime:這個時間是作為 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發(fā)送一個心跳。
  • dataDir:顧名思義就是 Zookeeper 保存數(shù)據(jù)的目錄,默認情況下,Zookeeper 將寫數(shù)據(jù)的日志文件也保存在這個目錄里。
  • clientPort:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監(jiān)聽這個端口,接受客戶端的訪問請求。

當這些配置項配置好后,你現(xiàn)在就可以啟動 Zookeeper 了,啟動后要檢查 Zookeeper 是否已經(jīng)在服務,可以通過 netstat – ano 命令查看是否有你配置的 clientPort 端口號在監(jiān)聽服務。

集群模式

Zookeeper 不僅可以單機提供服務,同時也支持多機組成集群來提供服務。實際上 Zookeeper 還支持另外一種偽集群的方式,也就是可以在一臺物理機上運行多個 Zookeeper 實例,下面將介紹集群模式的安裝和配置。

Zookeeper 的集群模式的安裝和配置也不是很復雜,所要做的就是增加幾個配置項。集群模式除了上面的三個配置項還要增加下面幾個配置項:

 initLimit=5 
 syncLimit=2 
 server.1=192.168.211.1:2888:3888 
 server.2=192.168.211.2:2888:3888
  • initLimit:這個配置項是用來配置 Zookeeper 接受客戶端(這里所說的客戶端不是用戶連接 Zookeeper 服務器的客戶端,而是 Zookeeper 服務器集群中連接到 Leader 的 Follower 服務器)初始化連接時最長能忍受多少個心跳時間間隔數(shù)。當已經(jīng)超過 10 個心跳的時間(也就是 tickTime)長度后 Zookeeper 服務器還沒有收到客戶端的返回信息,那么表明這個客戶端連接失敗。總的時間長度就是 5*2000=10 秒
  • syncLimit:這個配置項標識 Leader 與 Follower 之間發(fā)送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 2*2000=4 秒
  • server.A=B:C:D:其中 A 是一個數(shù)字,表示這個是第幾號服務器;B 是這個服務器的 ip 地址;C 表示的是這個服務器與集群中的 Leader 服務器交換信息的端口;D 表示的是萬一集群中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執(zhí)行選舉時服務器相互通信的端口。如果是偽集群的配置方式,由于 B 都是一樣,所以不同的 Zookeeper 實例通信端口號不能一樣,所以要給它們分配不同的端口號。

除了修改 zoo.cfg 配置文件,集群模式下還要配置一個文件 myid,這個文件在 dataDir 目錄下,這個文件里面就有一個數(shù)據(jù)就是 A 的值,Zookeeper 啟動時會讀取這個文件,拿到里面的數(shù)據(jù)與 zoo.cfg 里面的配置信息比較從而判斷到底是那個 server。

數(shù)據(jù)模型

Zookeeper 會維護一個具有層次關系的數(shù)據(jù)結構,它非常類似于一個標準的文件系統(tǒng),如圖 1 所示:

圖 1 Zookeeper 數(shù)據(jù)結構
圖 1 Zookeeper 數(shù)據(jù)結構

Zookeeper 這種數(shù)據(jù)結構有如下這些特點:

  1. 每個子目錄項如 NameService 都被稱作為 znode,這個 znode 是被它所在的路徑唯一標識,如 Server1 這個 znode 的標識為 /NameService/Server1
  2. znode 可以有子節(jié)點目錄,并且每個 znode 可以存儲數(shù)據(jù),注意 EPHEMERAL 類型的目錄節(jié)點不能有子節(jié)點目錄
  3. znode 是有版本的,每個 znode 中存儲的數(shù)據(jù)可以有多個版本,也就是一個訪問路徑中可以存儲多份數(shù)據(jù)
  4. znode 可以是臨時節(jié)點,一旦創(chuàng)建這個 znode 的客戶端與服務器失去聯(lián)系,這個 znode 也將自動刪除,Zookeeper 的客戶端和服務器通信采用長連接方式,每個客戶端和服務器通過心跳來保持連接,這個連接狀態(tài)稱為 session,如果 znode 是臨時節(jié)點,這個 session 失效,znode 也就刪除了
  5. znode 的目錄名可以自動編號,如 App1 已經(jīng)存在,再創(chuàng)建的話,將會自動命名為 App2
  6. znode 可以被監(jiān)控,包括這個目錄節(jié)點中存儲的數(shù)據(jù)的修改,子節(jié)點目錄的變化等,一旦變化可以通知設置監(jiān)控的客戶端,這個是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基于這個特性實現(xiàn)的,后面在典型的應用場景中會有實例介紹

如何使用

Zookeeper 作為一個分布式的服務框架,主要用來解決分布式集群中應用系統(tǒng)的一致性問題,它能提供基于類似于文件系統(tǒng)的目錄節(jié)點樹方式的數(shù)據(jù)存儲,但是 Zookeeper 并不是用來專門存儲數(shù)據(jù)的,它的作用主要是用來維護和監(jiān)控你存儲的數(shù)據(jù)的狀態(tài)變化。通過監(jiān)控這些數(shù)據(jù)狀態(tài)的變化,從而可以達到基于數(shù)據(jù)的集群管理,后面將會詳細介紹 Zookeeper 能夠解決的一些典型問題,這里先介紹一下,Zookeeper 的操作接口和簡單使用示例。

常用接口列表

客戶端要連接 Zookeeper 服務器可以通過創(chuàng)建 org.apache.zookeeper. ZooKeeper 的一個實例對象,然后調(diào)用這個類提供的接口來和服務器交互。

前面說了 ZooKeeper 主要是用來維護和監(jiān)控一個目錄節(jié)點樹中存儲的數(shù)據(jù)的狀態(tài),所有我們能夠操作 ZooKeeper 的也和操作目錄節(jié)點樹大體一樣,如創(chuàng)建一個目錄節(jié)點,給某個目錄節(jié)點設置數(shù)據(jù),獲取某個目錄節(jié)點的所有子目錄節(jié)點,給某個目錄節(jié)點設置權限和監(jiān)控這個目錄節(jié)點的狀態(tài)變化。

這些接口如下表所示:

表 1 org.apache.zookeeper. ZooKeeper 方法列表
方法名 方法功能描述
Stringcreate(String path, byte[] data, List<ACL> acl,CreateMode createMode) 創(chuàng)建一個給定的目錄節(jié)點 path, 并給它設置數(shù)據(jù),CreateMode 標識有四種形式的目錄節(jié)點,分別是 PERSISTENT:持久化目錄節(jié)點,這個目錄節(jié)點存儲的數(shù)據(jù)不會丟失;PERSISTENT_SEQUENTIAL:順序自動編號的目錄節(jié)點,這種目錄節(jié)點會根據(jù)當前已近存在的節(jié)點數(shù)自動加 1,然后返回給客戶端已經(jīng)成功創(chuàng)建的目錄節(jié)點名;EPHEMERAL:臨時目錄節(jié)點,一旦創(chuàng)建這個節(jié)點的客戶端與服務器端口也就是 session 超時,這種節(jié)點會被自動刪除;EPHEMERAL_SEQUENTIAL:臨時自動編號節(jié)點
Statexists(String path, boolean watch) 判斷某個 path 是否存在,并設置是否監(jiān)控這個目錄節(jié)點,這里的 watcher 是在創(chuàng)建 ZooKeeper 實例時指定的 watcher,exists方法還有一個重載方法,可以指定特定的 watcher
Statexists(String path,Watcher watcher) 重載方法,這里給某個目錄節(jié)點設置特定的 watcher,Watcher 在 ZooKeeper 是一個核心功能,Watcher 可以監(jiān)控目錄節(jié)點的數(shù)據(jù)變化以及子目錄的變化,一旦這些狀態(tài)發(fā)生變化,服務器就會通知所有設置在這個目錄節(jié)點上的 Watcher,從而每個客戶端都很快知道它所關注的目錄節(jié)點的狀態(tài)發(fā)生變化,而做出相應的反應
void delete(String path, int version) 刪除 path 對應的目錄節(jié)點,version 為 -1 可以匹配任何版本,也就刪除了這個目錄節(jié)點所有數(shù)據(jù)
List<String>getChildren(String path, boolean watch) 獲取指定 path 下的所有子目錄節(jié)點,同樣 getChildren方法也有一個重載方法可以設置特定的 watcher 監(jiān)控子節(jié)點的狀態(tài)
StatsetData(String path, byte[] data, int version) 給 path 設置數(shù)據(jù),可以指定這個數(shù)據(jù)的版本號,如果 version 為 -1 怎可以匹配任何版本
byte[] getData(String path, boolean watch, Stat stat) 獲取這個 path 對應的目錄節(jié)點存儲的數(shù)據(jù),數(shù)據(jù)的版本等信息可以通過 stat 來指定,同時還可以設置是否監(jiān)控這個目錄節(jié)點數(shù)據(jù)的狀態(tài)
voidaddAuthInfo(String scheme, byte[] auth) 客戶端將自己的授權信息提交給服務器,服務器將根據(jù)這個授權信息驗證客戶端的訪問權限。
StatsetACL(String path,List<ACL> acl, int version) 給某個目錄節(jié)點重新設置訪問權限,需要注意的是 Zookeeper 中的目錄節(jié)點權限不具有傳遞性,父目錄節(jié)點的權限不能傳遞給子目錄節(jié)點。目錄節(jié)點 ACL 由兩部分組成:perms 和 id。
Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 幾種 
而 id 標識了訪問目錄節(jié)點的身份列表,默認情況下有以下兩種:
ANYONE_ID_UNSAFE = new Id("world", "anyone") 和 AUTH_IDS = new Id("auth", "") 分別表示任何人都可以訪問和創(chuàng)建者擁有訪問權限。
List<ACL>getACL(String path,Stat stat) 獲取某個目錄節(jié)點的訪問權限列表

除了以上這些上表中列出的方法之外還有一些重載方法,如都提供了一個回調(diào)類的重載方法以及可以設置特定 Watcher 的重載方法,具體的方法可以參考 org.apache.zookeeper. ZooKeeper 類的 API 說明。

基本操作

下面給出基本的操作 ZooKeeper 的示例代碼,這樣你就能對 ZooKeeper 有直觀的認識了。下面的清單包括了創(chuàng)建與 ZooKeeper 服務器的連接以及最基本的數(shù)據(jù)操作:

清單 2. ZooKeeper 基本的操作示例
 // 創(chuàng)建一個與服務器的連接
 ZooKeeper zk = new ZooKeeper("localhost:" + CLIENT_PORT, 
        ClientBase.CONNECTION_TIMEOUT, new Watcher() { 
            // 監(jiān)控所有被觸發(fā)的事件
            public void process(WatchedEvent event) { 
                System.out.println("已經(jīng)觸發(fā)了" + event.getType() + "事件!"); 
            } 
        }); 
 // 創(chuàng)建一個目錄節(jié)點
 zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,
   CreateMode.PERSISTENT); 
 // 創(chuàng)建一個子目錄節(jié)點
 zk.create("/testRootPath/testChildPathOne", "testChildDataOne".getBytes(),
   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); 
 System.out.println(new String(zk.getData("/testRootPath",false,null))); 
 // 取出子目錄節(jié)點列表
 System.out.println(zk.getChildren("/testRootPath",true)); 
 // 修改子目錄節(jié)點數(shù)據(jù)
 zk.setData("/testRootPath/testChildPathOne","modifyChildDataOne".getBytes(),-1); 
 System.out.println("目錄節(jié)點狀態(tài):["+zk.exists("/testRootPath",true)+"]"); 
 // 創(chuàng)建另外一個子目錄節(jié)點
 zk.create("/testRootPath/testChildPathTwo", "testChildDataTwo".getBytes(), 
   Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); 
 System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo",true,null))); 
 // 刪除子目錄節(jié)點
 zk.delete("/testRootPath/testChildPathTwo",-1); 
 zk.delete("/testRootPath/testChildPathOne",-1); 
 // 刪除父目錄節(jié)點
 zk.delete("/testRootPath",-1); 
 // 關閉連接
 zk.close();

輸出的結果如下:

已經(jīng)觸發(fā)了 None 事件!
 testRootData 
 [testChildPathOne] 
目錄節(jié)點狀態(tài):[5,5,1281804532336,1281804532336,0,1,0,0,12,1,6] 
已經(jīng)觸發(fā)了 NodeChildrenChanged 事件!
 testChildDataTwo 
已經(jīng)觸發(fā)了 NodeDeleted 事件!
已經(jīng)觸發(fā)了 NodeDeleted 事件!

當對目錄節(jié)點監(jiān)控狀態(tài)打開時,一旦目錄節(jié)點的狀態(tài)發(fā)生變化,Watcher 對象的 process 方法就會被調(diào)用。

ZooKeeper 典型的應用場景

Zookeeper 從設計模式角度來看,是一個基于觀察者模式設計的分布式服務管理框架,它負責存儲和管理大家都關心的數(shù)據(jù),然后接受觀察者的注冊,一旦這些數(shù)據(jù)的狀態(tài)發(fā)生變化,Zookeeper 就將負責通知已經(jīng)在 Zookeeper 上注冊的那些觀察者做出相應的反應,從而實現(xiàn)集群中類似 Master/Slave 管理模式,關于 Zookeeper 的詳細架構等內(nèi)部細節(jié)可以閱讀 Zookeeper 的源碼

下面詳細介紹這些典型的應用場景,也就是 Zookeeper 到底能幫我們解決那些問題?下面將給出答案。

統(tǒng)一命名服務(Name Service)

分布式應用中,通常需要有一套完整的命名規(guī)則,既能夠產(chǎn)生唯一的名稱又便于人識別和記住,通常情況下用樹形的名稱結構是一個理想的選擇,樹形的名稱結構是一個有層次的目錄結構,既對人友好又不會重復。說到這里你可能想到了 JNDI,沒錯 Zookeeper 的 Name Service 與 JNDI 能夠完成的功能是差不多的,它們都是將有層次的目錄結構關聯(lián)到一定資源上,但是 Zookeeper 的 Name Service 更加是廣泛意義上的關聯(lián),也許你并不需要將名稱關聯(lián)到特定資源上,你可能只需要一個不會重復名稱,就像數(shù)據(jù)庫中產(chǎn)生一個唯一的數(shù)字主鍵一樣。

Name Service 已經(jīng)是 Zookeeper 內(nèi)置的功能,你只要調(diào)用 Zookeeper 的 API 就能實現(xiàn)。如調(diào)用 create 接口就可以很容易創(chuàng)建一個目錄節(jié)點。

配置管理(Configuration Management)

配置的管理在分布式應用環(huán)境中很常見,例如同一個應用系統(tǒng)需要多臺 PC Server 運行,但是它們運行的應用系統(tǒng)的某些配置項是相同的,如果要修改這些相同的配置項,那么就必須同時修改每臺運行這個應用系統(tǒng)的 PC Server,這樣非常麻煩而且容易出錯。

像這樣的配置信息完全可以交給 Zookeeper 來管理,將配置信息保存在 Zookeeper 的某個目錄節(jié)點中,然后將所有需要修改的應用機器監(jiān)控配置信息的狀態(tài),一旦配置信息發(fā)生變化,每臺應用機器就會收到 Zookeeper 的通知,然后從 Zookeeper 獲取新的配置信息應用到系統(tǒng)中。

圖 2. 配置管理結構圖
圖 2. 配置管理結構圖

集群管理(Group Membership)

Zookeeper 能夠很容易的實現(xiàn)集群管理的功能,如有多臺 Server 組成一個服務集群,那么必須要一個“總管”知道當前集群中每臺機器的服務狀態(tài),一旦有機器不能提供服務,集群中其它集群必須知道,從而做出調(diào)整重新分配服務策略。同樣當增加集群的服務能力時,就會增加一臺或多臺 Server,同樣也必須讓“總管”知道。

Zookeeper 不僅能夠幫你維護當前的集群中機器的服務狀態(tài),而且能夠幫你選出一個“總管”,讓這個總管來管理集群,這就是 Zookeeper 的另一個功能 Leader Election。

它們的實現(xiàn)方式都是在 Zookeeper 上創(chuàng)建一個 EPHEMERAL 類型的目錄節(jié)點,然后每個 Server 在它們創(chuàng)建目錄節(jié)點的父目錄節(jié)點上調(diào)用getChildren(String path, boolean watch) 方法并設置 watch 為 true,由于是 EPHEMERAL 目錄節(jié)點,當創(chuàng)建它的 Server 死去,這個目錄節(jié)點也隨之被刪除,所以 Children 將會變化,這時 getChildren上的 Watch 將會被調(diào)用,所以其它 Server 就知道已經(jīng)有某臺 Server 死去了。新增 Server 也是同樣的原理。

Zookeeper 如何實現(xiàn) Leader Election,也就是選出一個 Master Server。和前面的一樣每臺 Server 創(chuàng)建一個 EPHEMERAL 目錄節(jié)點,不同的是它還是一個 SEQUENTIAL 目錄節(jié)點,所以它是個 EPHEMERAL_SEQUENTIAL 目錄節(jié)點。之所以它是 EPHEMERAL_SEQUENTIAL 目錄節(jié)點,是因為我們可以給每臺 Server 編號,我們可以選擇當前是最小編號的 Server 為 Master,假如這個最小編號的 Server 死去,由于是 EPHEMERAL 節(jié)點,死去的 Server 對應的節(jié)點也被刪除,所以當前的節(jié)點列表中又出現(xiàn)一個最小編號的節(jié)點,我們就選擇這個節(jié)點為當前 Master。這樣就實現(xiàn)了動態(tài)選擇 Master,避免了傳統(tǒng)意義上單 Master 容易出現(xiàn)單點故障的問題。

圖 3. 集群管理結構圖
圖 3. 集群管理結構圖

這部分的示例代碼如下,完整的代碼請看附件:

清單 3. Leader Election 關鍵代碼
 void findLeader() throws InterruptedException { 
        byte[] leader = null; 
        try { 
            leader = zk.getData(root + "/leader", true, null); 
        } catch (Exception e) { 
            logger.error(e); 
        } 
        if (leader != null) { 
            following(); 
        } else { 
            String newLeader = null; 
            try { 
                byte[] localhost = InetAddress.getLocalHost().getAddress(); 
                newLeader = zk.create(root + "/leader", localhost, 
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); 
            } catch (Exception e) { 
                logger.error(e); 
            } 
            if (newLeader != null) { 
                leading(); 
            } else { 
                mutex.wait(); 
            } 
        } 
    }

共享鎖(Locks)

共享鎖在同一個進程中很容易實現(xiàn),但是在跨進程或者在不同 Server 之間就不好實現(xiàn)了。Zookeeper 卻很容易實現(xiàn)這個功能,實現(xiàn)方式也是需要獲得鎖的 Server 創(chuàng)建一個 EPHEMERAL_SEQUENTIAL 目錄節(jié)點,然后調(diào)用 getChildren方法獲取當前的目錄節(jié)點列表中最小的目錄節(jié)點是不是就是自己創(chuàng)建的目錄節(jié)點,如果正是自己創(chuàng)建的,那么它就獲得了這個鎖,如果不是那么它就調(diào)用 exists(String path, boolean watch) 方法并監(jiān)控 Zookeeper 上目錄節(jié)點列表的變化,一直到自己創(chuàng)建的節(jié)點是列表中最小編號的目錄節(jié)點,從而獲得鎖,釋放鎖很簡單,只要刪除前面它自己所創(chuàng)建的目錄節(jié)點就行了。

圖 4. Zookeeper 實現(xiàn) Locks 的流程圖
圖 4. Zookeeper 實現(xiàn) Locks 的流程圖

同步鎖的實現(xiàn)代碼如下,完整的代碼請看附件:

清單 4. 同步鎖的關鍵代碼
 void getLock() throws KeeperException, InterruptedException{ 
        List<String> list = zk.getChildren(root, false); 
        String[] nodes = list.toArray(new String[list.size()]); 
        Arrays.sort(nodes); 
        if(myZnode.equals(root+"/"+nodes[0])){ 
            doAction(); 
        } 
        else{ 
            waitForLock(nodes[0]); 
        } 
    } 
    void waitForLock(String lower) throws InterruptedException, KeeperException {
        Stat stat = zk.exists(root + "/" + lower,true); 
        if(stat != null){ 
            mutex.wait(); 
        } 
        else{ 
            getLock(); 
        } 
    }

隊列管理

Zookeeper 可以處理兩種類型的隊列:

  1. 當一個隊列的成員都聚齊時,這個隊列才可用,否則一直等待所有成員到達,這種是同步隊列。
  2. 隊列按照 FIFO 方式進行入隊和出隊操作,例如實現(xiàn)生產(chǎn)者和消費者模型。

同步隊列用 Zookeeper 實現(xiàn)的實現(xiàn)思路如下:

創(chuàng)建一個父目錄 /synchronizing,每個成員都監(jiān)控標志(Set Watch)位目錄 /synchronizing/start 是否存在,然后每個成員都加入這個隊列,加入隊列的方式就是創(chuàng)建 /synchronizing/member_i 的臨時目錄節(jié)點,然后每個成員獲取 / synchronizing 目錄的所有目錄節(jié)點,也就是 member_i。判斷 i 的值是否已經(jīng)是成員的個數(shù),如果小于成員個數(shù)等待 /synchronizing/start 的出現(xiàn),如果已經(jīng)相等就創(chuàng)建 /synchronizing/start。

用下面的流程圖更容易理解:

圖 5. 同步隊列流程圖
圖 5. 同步隊列流程圖

同步隊列的關鍵代碼如下,完整的代碼請看附件:

清單 5. 同步隊列
 void addQueue() throws KeeperException, InterruptedException{ 
        zk.exists(root + "/start",true); 
        zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE, 
        CreateMode.EPHEMERAL_SEQUENTIAL); 
        synchronized (mutex) { 
            List<String> list = zk.getChildren(root, false); 
            if (list.size() < size) { 
                mutex.wait(); 
            } else { 
                zk.create(root + "/start", new byte[0], Ids.OPEN_ACL_UNSAFE,
                 CreateMode.PERSISTENT); 
            } 
        } 
 }

當隊列沒滿是進入 wait(),然后會一直等待 Watch 的通知,Watch 的代碼如下:

 public void process(WatchedEvent event) { 
        if(event.getPath().equals(root + "/start") &&
         event.getType() == Event.EventType.NodeCreated){ 
            System.out.println("得到通知"); 
            super.process(event); 
            doAction(); 
        } 
    }

FIFO 隊列用 Zookeeper 實現(xiàn)思路如下:

實現(xiàn)的思路也非常簡單,就是在特定的目錄下創(chuàng)建 SEQUENTIAL 類型的子目錄 /queue_i,這樣就能保證所有成員加入隊列時都是有編號的,出隊列時通過 getChildren( ) 方法可以返回當前所有的隊列中的元素,然后消費其中最小的一個,這樣就能保證 FIFO。

下面是生產(chǎn)者和消費者這種隊列形式的示例代碼,完整的代碼請看附件:

清單 6. 生產(chǎn)者代碼
 boolean produce(int i) throws KeeperException, InterruptedException{ 
        ByteBuffer b = ByteBuffer.allocate(4); 
        byte[] value; 
        b.putInt(i); 
        value = b.array(); 
        zk.create(root + "/element", value, ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.PERSISTENT_SEQUENTIAL); 
        return true; 
    }
清單 7. 消費者代碼
 int consume() throws KeeperException, InterruptedException{ 
        int retvalue = -1; 
        Stat stat = null; 
        while (true) { 
            synchronized (mutex) { 
                List<String> list = zk.getChildren(root, true); 
                if (list.size() == 0) { 
                    mutex.wait(); 
                } else { 
                    Integer min = new Integer(list.get(0).substring(7)); 
                    for(String s : list){ 
                        Integer tempValue = new Integer(s.substring(7)); 
                        if(tempValue < min) min = tempValue; 
                    } 
                    byte[] b = zk.getData(root + "/element" + min,false, stat); 
                    zk.delete(root + "/element" + min, 0); 
                    ByteBuffer buffer = ByteBuffer.wrap(b); 
                    retvalue = buffer.getInt(); 
                    return retvalue; 
                } 
            } 
        } 
 }

總結

Zookeeper 作為 Hadoop 項目中的一個子項目,是 Hadoop 集群管理的一個必不可少的模塊,它主要用來控制集群中的數(shù)據(jù),如它管理 Hadoop 集群中的 NameNode,還有 Hbase 中 Master Election、Server 之間狀態(tài)同步等。

本文介紹的 Zookeeper 的基本知識,以及介紹了幾個典型的應用場景。這些都是 Zookeeper 的基本功能,最重要的是 Zoopkeeper 提供了一套很好的分布式集群管理的機制,就是它這種基于層次型的目錄樹的數(shù)據(jù)結構,并對樹中的節(jié)點進行有效管理,從而可以設計出多種多樣的分布式的數(shù)據(jù)管理模型,而不僅僅局限于上面提到的幾個常用應用場景。

下載

描述 名字 大小
樣例代碼 sample.rar 8KB



posted on 2017-02-27 11:24 思月行云 閱讀(746) 評論(0)  編輯 收藏 引用 所屬分類: 分布式\MQ
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲视频高清| 老司机免费视频久久| 亚洲日本无吗高清不卡| 美女视频一区免费观看| 亚洲国产精品va在线看黑人| 久久麻豆一区二区| 欧美+亚洲+精品+三区| 亚洲精品一区二区在线观看| 亚洲精品免费一区二区三区| 国产精品r级在线| 久久成人精品电影| 免费观看亚洲视频大全| 亚洲在线播放| 久久频这里精品99香蕉| 一区二区三区成人| 午夜在线观看免费一区| 亚洲国产一区二区三区青草影视| 亚洲人成毛片在线播放| 国产午夜精品久久久| 牛人盗摄一区二区三区视频| 欧美日韩国产综合一区二区| 欧美资源在线观看| 欧美成人午夜77777| 欧美亚洲综合网| 免费在线欧美黄色| 欧美一级大片在线观看| 久久午夜国产精品| 欧美在线一区二区三区| 欧美本精品男人aⅴ天堂| 欧美一二三区在线观看| 欧美精品一区二区久久婷婷| 欧美亚洲综合另类| 欧美日韩三级| 欧美成人一区二免费视频软件| 国产精品高潮在线| 亚洲人成网站精品片在线观看| 国产日韩精品一区| 99视频精品在线| 亚洲黄色尤物视频| 欧美在线国产精品| 亚洲一区二区三区四区五区午夜| 久久免费视频在线| 久久精品一区二区三区不卡| 欧美日韩一区二区三区免费看| 老色批av在线精品| 国产欧美日韩视频一区二区三区 | 国产精品美女久久久| 欧美成人一区二区在线| 国产亚洲一区二区精品| 亚洲婷婷综合久久一本伊一区| 亚洲精品在线观看免费| 久久亚洲私人国产精品va| 久久国产精品亚洲va麻豆| 欧美sm重口味系列视频在线观看| 久久激情视频久久| 欧美一区二区三区四区夜夜大片| 欧美激情网站在线观看| 欧美激情一区二区三区不卡| 亚洲电影天堂av| 久久夜色精品国产| 美女尤物久久精品| 尤妮丝一区二区裸体视频| 久久久久久久综合色一本| 亚洲男人影院| 一区二区在线视频| 久久激情五月丁香伊人| 久久久99精品免费观看不卡| 国产精品视频一区二区高潮| 亚洲一区二区在线视频| 欧美一区二区视频在线观看2020 | 欧美中在线观看| 久久久久国内| 亚洲第一在线综合在线| 欧美jizzhd精品欧美喷水 | 亚洲在线免费| 国产精品青草久久| 午夜伦欧美伦电影理论片| 久久久久久久精| 亚洲国产日韩美| 欧美日韩高清在线观看| 亚洲视频欧美在线| 久久久久免费| 亚洲人成在线观看| 欧美日韩中文精品| 小嫩嫩精品导航| 免费久久99精品国产自| 日韩视频在线免费| 国产欧美精品| 欧美成人午夜激情视频| 一区二区三区导航| 久久久亚洲精品一区二区三区| 在线免费观看一区二区三区| 欧美日韩二区三区| 欧美在线免费播放| 亚洲精品1区| 羞羞色国产精品| 91久久国产综合久久| 国产精品久久久久久久久久久久久久| 午夜精品久久久99热福利| 久久综合久色欧美综合狠狠| 日韩亚洲视频| 国产一区亚洲| 欧美日韩中文字幕在线| 久久精品国产亚洲aⅴ| 亚洲精品人人| 麻豆精品一区二区综合av| 亚洲永久字幕| 亚洲国产午夜| 韩日欧美一区二区| 欧美午夜不卡视频| 免费观看国产成人| 欧美专区在线| 亚洲直播在线一区| 亚洲精品在线观| 欧美成人免费网| 久久久精品网| 午夜在线精品偷拍| 一本色道久久综合精品竹菊| 一区免费观看| 国产午夜精品理论片a级大结局| 欧美理论视频| 免费不卡中文字幕视频| 久久精品视频va| 久久噜噜噜精品国产亚洲综合| 国产精品爱久久久久久久| 欧美大胆成人| 麻豆成人在线播放| 久久久久欧美| 久久se精品一区精品二区| 亚洲一区二区三区视频播放| 日韩亚洲欧美成人| 中文国产成人精品| 日韩午夜av| 亚洲靠逼com| 亚洲国产日韩欧美| 亚洲人体偷拍| 91久久一区二区| 亚洲黄色免费网站| 亚洲免费电影在线观看| 亚洲精品视频一区二区三区| 亚洲国产精品99久久久久久久久| 在线观看久久av| 影视先锋久久| 91久久线看在观草草青青| 亚洲精品久久久一区二区三区| 在线日韩电影| 亚洲精品视频在线播放| 一区二区精品| 性久久久久久久久| 久久久久久久久伊人| 久久综合伊人| 亚洲成色999久久网站| 欧美一级播放| 久久午夜电影网| 欧美激情一二三区| 日韩午夜电影在线观看| 亚洲综合欧美| 久久精品国产综合| 免费亚洲电影在线| 欧美日韩成人一区二区| 国产精品一级| 亚洲国产精品悠悠久久琪琪| 亚洲精品一二三| 亚洲欧美激情四射在线日| 久久精品国产99国产精品| 女女同性精品视频| 亚洲乱码国产乱码精品精98午夜 | 久久综合免费视频影院| 亚洲福利电影| 亚洲无线一线二线三线区别av| 久久精品动漫| 欧美日韩在线不卡| 国产一区二区剧情av在线| 亚洲国产日韩美| 性欧美1819sex性高清| 欧美黄色aaaa| 亚洲性夜色噜噜噜7777| 久久久久久久999| 国产精品久久9| 亚洲激情自拍| 欧美亚洲专区| 亚洲人屁股眼子交8| 久久成人国产| 国产精品嫩草久久久久| 亚洲高清免费视频| 欧美一区二区三区在线看| 亚洲国产精品ⅴa在线观看| 亚洲在线第一页| 欧美国产综合| 伊人成人在线| 香蕉成人伊视频在线观看| 欧美激情亚洲精品| 欧美一区日韩一区| 国产精品magnet| 亚洲电影专区| 久久青青草综合| 亚洲一区在线播放| 欧美日精品一区视频| 亚洲精品综合精品自拍| 六月婷婷久久|