轉載來源:https://www.cnblogs.com/sunddenly/p/4031881.html
1、Zookeeper的四字命令
Zookeeper支持某些特定的四字命令字母與其的交互。他們大多數是查詢命令,用來獲取Zookeeper服務的當前狀態及相關信息。用戶在客戶端能夠經過telnet或nc向Zookeeper提交相應的命令。Zookeeper經常使用的四字命令見下圖所示。javascript
上圖,是Zookeeper四字命令的一個簡單用例。html
[root@hadoop ~]# echo ruok|nc localhost 2181 [root@hadoop ~]# zkServer.sh start zoo1.cfg JMX enabled by default Using config: /usr/local/zk/bin/../conf/zoo1.cfg Starting zookeeper ... STARTED [root@hadoop ~]# zkServer.sh start zoo2.cfg JMX enabled by default Using config: /usr/local/zk/bin/../conf/zoo2.cfg Starting zookeeper ... STARTED [root@hadoop ~]# zkServer.sh start zoo3.cfg JMX enabled by default Using config: /usr/local/zk/bin/../conf/zoo3.cfg Starting zookeeper ... STARTED [root@hadoop ~]# echo ruok|nc localhost 2181 imok[root@hadoop ~]# echo ruok|nc localhost 2182 imok[root@hadoop ~]# echo ruok|nc localhost 2183 imok[root@hadoop ~]# echo conf|nc localhost 2181 clientPort=2181 dataDir=/usr/local/zk/data_1/version-2 dataLogDir=/usr/local/zk/logs_1/version-2 tickTime=2000 maxClientCnxns=60 minSessionTimeout=4000 maxSessionTimeout=40000 serverId=0 initLimit=10 syncLimit=5 electionAlg=3 electionPort=3387 quorumPort=2287 peerType=0 [root@hadoop ~]#
2、Zookeeper的簡單操做
2.1 Zookeeper的shell操做
2.1.1 Zookeeper命令工具
再啓動Zookeeper服務以後,輸入如下命令,鏈接到Zookeeper服務:java
zkCli.sh -server localhost:2181node
執行結果以下所示:shell
[root@hadoop ~]# zkCli.sh -server localhost:2181 Connecting to localhost:2181 2014-10-17 03:35:51,051 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.5-1392090, built on 09/30/2012 17:52 GMT 2014-10-17 03:35:51,055 [myid:] - INFO [main:Environment@100] - Client environment:host.name=hadoop 2014-10-17 03:35:51,057 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.6.0_24 2014-10-17 03:35:51,057 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Sun Microsystems Inc. 2014-10-17 03:35:51,066 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/usr/local/jdk/jre 2014-10-17 03:35:51,079 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/usr/local/zk/bin/../build/classes:/usr/local/zk/bin/../build/lib/*.jar:/usr/local/zk/bin/../lib/slf4j-log4j12-1.6.1.jar:/usr/local/zk/bin/../lib/slf4j-api-1.6.1.jar:/usr/local/zk/bin/../lib/netty-3.2.2.Final.jar:/usr/local/zk/bin/../lib/log4j-1.2.15.jar:/usr/local/zk/bin/../lib/jline-0.9.94.jar:/usr/local/zk/bin/../zookeeper-3.4.5.jar:/usr/local/zk/bin/../src/java/lib/*.jar:/usr/local/zk/bin/../conf: 2014-10-17 03:35:51,083 [myid:] - INFO [main:Environment@100] - Client environment:java.library.path=/usr/local/jdk/jre/lib/i386/client:/usr/local/jdk/jre/lib/i386:/usr/local/jdk/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib 2014-10-17 03:35:51,084 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp 2014-10-17 03:35:51,086 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=<NA> 2014-10-17 03:35:51,099 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux 2014-10-17 03:35:51,100 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=i386 2014-10-17 03:35:51,101 [myid:] - INFO [main:Environment@100] - Client environment:os.version=2.6.32-358.el6.i686 2014-10-17 03:35:51,101 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root 2014-10-17 03:35:51,102 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root 2014-10-17 03:35:51,106 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/root 2014-10-17 03:35:51,120 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@b02e7a Welcome to ZooKeeper! JLine support is enabled 2014-10-17 03:35:51,233 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@966] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (Unable to locate a login configuration) 2014-10-17 03:35:51,247 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@849] - Socket connection established to localhost/127.0.0.1:2181, initiating session [zk: localhost:2181(CONNECTING) 0] 2014-10-17 03:35:51,290 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1207] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x491da0e20b0000, negotiated timeout = 30000 WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: localhost:2181(CONNECTED) 0]
鏈接成功以後,系統會輸出Zookeeper的相關環境及配置信息,並在屏幕輸出「welcome to Zookeeper!」等信息。輸入help以後,屏幕會輸出可用的Zookeeper命令,以下圖所示apache
2.1.2 使用Zookeeper命令的簡單操做步驟
(1) 使用ls命令查看當前Zookeeper中所包含的內容:ls /編程
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 2]
(2) 建立一個新的Znode節點"zk",以及和它相關字符,執行命令:create /zk myDataapi
[zk: localhost:2181(CONNECTED) 2] create /zk myData
Created /zk
(3) 再次使用ls命令來查看如今Zookeeper的中所包含的內容:ls /數組
[zk: localhost:2181(CONNECTED) 3] ls /
[zk, zookeeper]
此時看到,zk節點已經被建立。 服務器
(4) 使用get命令來確認第二步中所建立的Znode是否包含咱們建立的字符串,執行命令:get /zk
[zk: localhost:2181(CONNECTED) 4] get /zk
myData
cZxid = 0x500000006
ctime = Fri Oct 17 03:54:20 PDT 2014
mZxid = 0x500000006
mtime = Fri Oct 17 03:54:20 PDT 2014
pZxid = 0x500000006
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
(5) 接下來經過set命令來對zk所關聯的字符串進行設置,執行命令:set /zk jiang1234
[zk: localhost:2181(CONNECTED) 5] set /zk jiang2014
cZxid = 0x500000006
ctime = Fri Oct 17 03:54:20 PDT 2014
mZxid = 0x500000007
mtime = Fri Oct 17 03:55:50 PDT 2014
pZxid = 0x500000006
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
(6) 再次使用get命令來查看,上次修改的內容,執行命令:get /zk
[zk: localhost:2181(CONNECTED) 6] get /zk
jiang2014
cZxid = 0x500000006
ctime = Fri Oct 17 03:54:20 PDT 2014
mZxid = 0x500000007
mtime = Fri Oct 17 03:55:50 PDT 2014
pZxid = 0x500000006
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
(7) 下面咱們將剛纔建立的Znode刪除,執行命令:delete /zk
[zk: localhost:2181(CONNECTED) 7] delete /zk
(8) 最後再次使用ls命令查看Zookeeper中的內容,執行命令:ls /
[zk: localhost:2181(CONNECTED) 8] ls /
[zookeeper]
通過驗證,zk節點已經刪除。
2.2 Zookeeper的api的簡單使用
2.2.1 ZookeeperAPI簡介
Zookeeper API共包含五個包,分別爲:
(1)org.apache.zookeeper
(2)org.apache.zookeeper.data
(3)org.apache.zookeeper.server
(4)org.apache.zookeeper.server.quorum
(5)org.apache.zookeeper.server.upgrade
其中org.apache.zookeeper,包含Zookeeper類,他是咱們編程時最經常使用的類文件。這個類是Zookeeper客戶端的主要類文件。若是要使用Zookeeper服務,應用程序首先必須建立一個Zookeeper實例,這時就須要使用此類。一旦客戶端和Zookeeper服務創建起了鏈接,Zookeeper系統將會給次鏈接會話分配一個ID值,而且客戶端將會週期性的向服務器端發送心跳來維持會話鏈接。只要鏈接有效,客戶端就可使用Zookeeper API來作相應處理了。
Zookeeper類提供了以下圖所示的幾類主要方法
2.2.2 Zookeeper API的使用
這裏經過一個例子來簡單介紹如何使用Zookeeper API 編寫本身的應用程序,代碼以下:
package org.zk; import java.io.IOException; import java.util.List; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; public class ListGroup extends ConnectionWatcher { public void list(String groupNmae) throws KeeperException, InterruptedException{ String path ="/"+groupNmae; try { List<String> children = zk.getChildren(path, false); if(children.isEmpty()){ System.out.printf("No memebers in group %s\n",groupNmae); System.exit(1); } for(String child:children){ System.out.println(child); } } catch (KeeperException.NoNodeException e) { System.out.printf("Group %s does not exist \n", groupNmae); System.exit(1); } } public static void main(String[] args) throws IOException, InterruptedException, KeeperException { ListGroup listGroup = new ListGroup(); listGroup.connect(args[0]); listGroup.list(args[1]); listGroup.close(); } }
此類包含兩個主要的 ZooKeeper 函數,分別爲 createZKInstance ()和 ZKOperations()。其中:
(1) createZKInstance()函數負責對 ZooKeeper 實例 zk 進行初始化。
ZooKeeper 類有兩個構造函數,咱們這裏使用「 ZooKeeper (String connectString, int sessionTimeout ,Watcher watcher )」對其進行初始化。所以,咱們須要提供初始化所需的,鏈接字符串信息,會話超時時間,以及一個 watcher 實例。 19行到 25行代碼,是程序所構造的一個watcher 實例,它可以輸出所發生的事件。
(2) ZKOperations ()函數是咱們所定義的對節點的一系列操做。
它包括:建立 ZooKeeper 節點( 35行到 36行代碼)、查看節點( 38 行到 39 行代碼)、修改節點數據( 41 行到 42 行代碼)、查看修改後節點數據( 44 行到 45行代碼)、刪除節點( 47行到 48行代碼)、查看節點是否存在( 50 行到 51 行代碼)。
代碼的運行結果以下:
1. 建立ZooKeeper節點(Znode:/znode;數據:myData2;權限:OPEN_ACL_UNSAFE;節點類型:Persistent)
None
2. 查看節點是否建立成功:
/znode myData2
3. 修改節點數據:
4. 查看是否修改爲功:
jiang1234
5. 刪除節點:
6. 查看/znode節點狀態:
節點間狀態:[null]
3、ZooKeeper示例
假設一組服務器,用於爲客戶端提供一些服務。咱們但願每一個客戶端都可以可以找到其中一臺服務器,使其可以使用這些服務,挑戰之一就是維護這組服務器列表。這組服務器的成員列代表顯不能存在網絡中的單個節點上,由於若是那個節點發生故障,就意味着是整個系統的故障(咱們但願這個列表有很高的可用性)。假設咱們有了一個可靠的方法解決了這個成員列表的存儲問題。若是其中一臺服務器出現故障,咱們仍然須要解決如何從服務器成員列表中將它刪除的問題。某個進程須要負責刪除故障服務器,但注意不能由故障服務器本身來完成,由於故障服務器已經再也不運行。
咱們所描述的不是一個被動的分佈式數據結構,而是一個主動的、可以在某個外部事件發生時修改數據項狀態的數據結構。ZooKeeper提供這種服務,因此讓咱們看看如何使用它來實現這種衆所周知的組成員管理應用。
ZooKeeper中的組成員關係
理解ZooKeeper的一種方法就是將其看做一個具備高可用性的文件系統。但這個文件系統中沒有文件和目錄,而是統一使用「節點」(node)的概念,稱爲znode。znode既能夠做爲保存數據的容器(如同文件),也能夠做爲保存其餘znode的容器(如同目錄)。全部的znode構成一個層次化的命名空間。一種天然的創建組成員列表的方式就是利用這種層次結構,建立一個以組名爲節點名的znode做爲父節點,而後以組成員名(服務器名)爲節點名來建立做爲子節點的znode。以下圖給出了一組具備層次結構的znode。
在這個示例中,咱們沒有在任何znode中存儲數據,但在一個真實的應用中,你能夠將「關於成員的數據」存儲在它們的znode中,例如主機名。
3.1 建立組
3.1.1 代碼示例
讓咱們經過編寫一段程序的方式來再次詳細介紹ZooKeeper的Java API,這段示例程序用於爲組名爲/zoo的組建立一個znode。代碼參見以下
代碼 該程序在ZooKeeper中新建表示組的Znode
package org.zk; import java.io.IOException; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; public class CreateGroup implements Watcher{ private static final int SESSION_TIMEOUT=5000; private ZooKeeper zk; private CountDownLatch connectedSignal=new CountDownLatch(1); @Override public void process(WatchedEvent event) { if(event.getState()==KeeperState.SyncConnected){ connectedSignal.countDown(); } } public static void main(String[] args) throws IOException, InterruptedException, KeeperException { CreateGroup createGroup = new CreateGroup(); createGroup.connect(args[0]); createGroup.create(args[1]); createGroup.close(); } private void close() throws InterruptedException { zk.close(); } private void create(String groupName) throws KeeperException, InterruptedException { String path="/"+groupName; if(zk.exists(path, false)== null){ zk.create(path, null/*data*/, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } System.out.println("Created:"+path); } private void connect(String hosts) throws IOException, InterruptedException { zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this); connectedSignal.await(); } }
運行該程序須要配置classpath環境變量或者在執行java命令時添加-classpath選項,具體運行方式參見:http://www.cnblogs.com/sunddenly/p/4050812.html
運行後的結果爲:
[root@hadoop code]# ls
build classes CreateGroup.java HelloWorld.java jar.jar PackageTest.java zookeeper.out
[root@hadoop code]# javac -d ./classes CreateGroup.java
[root@hadoop code]# java org.zk.CreateGroup localhost:2181 zoo
2014-10-28 18:00:26,154 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.5-1392090, built on
2014-10-28 18:00:26,157 [myid:] - INFO [main:Environment@100] - Client environment:host.name=hadoop
2014-10-28 18:00:26,157 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.6.0_24
2014-10-28 18:00:26,157 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Sun Microsystems Inc.
2014-10-28 18:00:26,158 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/usr/local/jdk/jre
2014-10-28 18:00:26,158 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=……
……
Created:/zoo
2014-10-28 18:00:26,236 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x4956f7f1d70005 closed
2014-10-28 18:00:26,237 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@509] - EventThread shut down
[root@hadoop code]#
3.1.2 代碼分析
在上面代碼中,main()方法執行時,建立了一個CreateGroup的實例而且調用了這個實例的connect()方法。connect方法實例化了一個新的ZooKeeper類的對象,這個類是客戶端API中的主要類,而且負責維護客戶端和ZooKeeper服務之間的鏈接。ZooKeeper類的構造函數有三個參數:
第一個是:ZooKeeper服務的主機地址,可指定端口,默認端口是2181。
第二個是:以毫秒爲單位的會話超時參數,這裏咱們設成5秒。
第三個是:參數是一個Watcher對象的實例。
Watcher對象接收來自於ZooKeeper的回調,以得到各類事件的通知。在這個例子中,CreateGroup是一個Watcher對象,所以咱們將它傳遞給ZooKeeper的構造函數。
當一個ZooKeeper的實例被建立時,會啓動一個線程鏈接到ZooKeeper服務。因爲對構造函數的調用是當即返回的,所以在使用新建的ZooKeeper對象以前必定要等待其與ZooKeeper服務之間的鏈接創建成功。咱們使用Java的CountDownLatch類來阻止使用新建的ZooKeeper對象,直到這個ZooKeeper對象已經準備就緒。這就是Watcher類的
用途,在它的接口中只有一個方法:
public void process(WatcherEvent event);
客戶端已經與ZooKeeper創建鏈接後,Watcher的process()方法會被調用,參數是一個表示該鏈接的事件。在接收到一個鏈接事件(由Watcher.Event.KeeperState的枚舉型值SyncConnected來表示)時,咱們經過調用CountDownLatch的countDown()方法來遞減它的計數器。鎖存器(latch)被建立時帶有一個值爲1的計數器,用於表示在它釋放全部等待線程以前須要發生的事件數。在調用一歡countDown()方法以後,計數器的值變爲0,則await()方法返回。
如今connect()方法已經返回,下一個執行的是CreateGroup的create()方法。在這個方法中,咱們使用ZooKeeper實例中的create()方法來建立一個新的ZooKeeper的znode。所需的參數包括:
路徑:用字符串表示。
znode的內容:字節數組,本例中使用空值。
訪問控制列表:簡稱ACL,本例中使用了徹底開放的ACL,容許任何客戶端對znode進行讀寫。
建立znode的類型:有兩種類型的znode:短暫的和持久的。
建立znode的客戶端斷開鏈接時,不管客戶端是明確斷開仍是由於任何緣由而終止,短暫znode都會被ZooKeeper服務刪除。與之相反,當客戶端斷開鏈接時,持久znode不會被刪除。咱們但願表明一個組的znode存活的時間應當比建立程序的生命週期要長,所以在本例中咱們建立了一個持久的znode。
create()方法的返回值是ZooKeeper所建立的路徑,咱們用這個返回值來打印一條表示路徑成功建立的消息。當咱們查看「順序znode」(sequential znode)時.會發現create()方法返回的路徑與傳遞給該方法的路徑不一樣。
3.2 加入組
下面的這一段程序用於註冊組的成員。每一個組成員將做爲一個程序運行,而且加入到組中。當程序退出時,這個組成員應當從組中被刪除。爲了實現這一點,咱們在ZooKeeper的命名空間中使用短暫znode來表明一個組成員。
在基類ConnectionWatcher中,對建立和鏈接ZooKeeper實例的程序邏輯進行了重構,參見代碼以下
代碼 用於將成員加入組的程序
package org.zk; import java.io.IOException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs.Ids; public class JoinGroup extends ConnectionWatcher{ public void join(String groupName,String memberName) throws KeeperException, InterruptedException{ String path="/"+groupName+"/"+memberName; String createdPath=zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); System.out.println("Created:"+createdPath); } public static void main(String[] args) throws InterruptedException, IOException, KeeperException { JoinGroup joinGroup = new JoinGroup(); joinGroup.connect(args[0]); joinGroup.join(args[1], args[2]); //stay alive until process is killed or thread is interrupted Thread.sleep(Long.MAX_VALUE); } }
代碼 3.3 用於等待創建與ZooKeeper鏈接的輔助類
package org.zk; import java.io.IOException; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; public class ConnectionWatcher implements Watcher{ private static final int SESSION_TIMEOUT=5000; protected ZooKeeper zk; CountDownLatch connectedSignal=new CountDownLatch(1); public void connect(String host) throws IOException, InterruptedException{ zk=new ZooKeeper(host, SESSION_TIMEOUT, this); connectedSignal.await(); } @Override public void process(WatchedEvent event) { if(event.getState()==KeeperState.SyncConnected){ connectedSignal.countDown(); } } public void close() throws InterruptedException{ zk.close(); } }
JoinGroup的代碼與CreateGroup很是類似,在它的join()方法中,建立短暫znode,做爲組znode的子節點,而後經過休眠來模擬正在作某種工做,直到該進程被強行終止。接着,你會看到隨着進程終止,這個短暫znode被ZooKeeper刪除。
3.3 列出組成員
如今,咱們須要一段程序來查看組成員,參見代碼以下:
代碼 用於列出組成員的程序
package org.zk; import java.io.IOException; import java.util.List; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; public class ListGroup extends ConnectionWatcher { public void list(String groupNmae) throws KeeperException, InterruptedException{ String path ="/"+groupNmae; try { List<String> children = zk.getChildren(path, false); if(children.isEmpty()){ System.out.printf("No memebers in group %s\n",groupNmae); System.exit(1); } for(String child:children){ System.out.println(child); } } catch (KeeperException.NoNodeException e) { System.out.printf("Group %s does not exist \n", groupNmae); System.exit(1); } } public static void main(String[] args) throws IOException, InterruptedException, KeeperException { ListGroup listGroup = new ListGroup(); listGroup.connect(args[0]); listGroup.list(args[1]); listGroup.close(); } }
在list()方法中,咱們調用了getChildren()方法來檢索並打印輸出一個znode的子節點列表,調用參數爲:該znode的路徑和設爲false的觀察標誌。若是在一znode上設置了觀察標誌,那麼一旦該znode的狀態改變,關聯的觀察(Watcher)會被觸發。雖然在這裏咱們能夠不使用觀察,但在查看一個znode的子節點時,也能夠設置觀察,讓應用程序接收到組成員加入、退出和組被刪除的有關通知。
在這段程序中,咱們捕捉了KeeperException.NoNodeException異常,表明組的znode不存在時,這個異常就會被拋出。下面看一下ListGroup程序的工做過程:雖然搭建了分佈式的ZooKeeper,但分佈式ZooKeeper啓動運行比較耗時,我在這採用前面提到的複製模式下的ZooKeeper來進行測試。
首先咱們得啓動ZooKeeper,啓動之後將上面的源程序放到Linux目錄中並進行編譯,我將其放到了"/usr/code"目錄下,並在該目錄下建立一個classes文件夾,用於存放生成字節碼文件:
[root@hadoop ~]# cd /usr/code
[root@hadoop code]# ls
ConnectionWatcher.java DeleteGroup.java ListGroup.java
classes CreateGroup.java JoinGroup.java PackageTest.java
[root@hadoop code]# javac -d ./classes ConnectionWatcher.java
[root@hadoop code]# javac -d ./classes *.java
因爲目前咱們尚未在組中添加任何成員,所以zoo是空的:
[root@hadoop code]# java org.zk.ListGroup localhost zoo
2014-10-30 01:52:19,703 [myid:] - INFO [main:Environment@100] - Client environment:……
……
No memebers in group zoo
咱們可使用JoinGroup來向組中添加成員。在sleep語句的做用下,這些做爲組成員的znode不會本身終止,因此咱們能夠,之後臺進程的方式來啓動他們:
[root@hadoop code]# java org.zk.JoinGroup localhost zoo duck &
2014-10-30 02:06:05,018 [myid:] - INFO [main:Environment@100] - Client environment:……
……
Created:/zoo/duck
[root@hadoop code]# java org.zk.JoinGroup localhost zoo cow &
2014-10-30 02:06:05,018 [myid:] - INFO [main:Environment@100] - Client environment:……
……
Created:/zoo/cow
[root@hadoop code]# java org.zk.JoinGroup localhost zoo goat &
2014-10-30 02:06:05,018 [myid:] - INFO [main:Environment@100] - Client environment:……
……
Created:/zoo/goat
最後一行命令保存了將goat添加到組中的java進程的ID。咱們須要保存這個進程的ID,以便可以在查看組成員以後殺死進程。
[root@hadoop code]#
2014-10-30 03:15:30,619 [myid:] - INFO [main:Environment@100] - Client environment:……
……
duck
cow
goat
爲了從組中刪除一個成員,咱們殺死了goat所對應的進程:
[root@hadoop code]# kill $goat_pid
幾秒鐘以後,因爲進程的ZooKeeper會話已經結束(超時爲5秒),因此goat會從組成員列表消失,而且對應的短暫znode也已經被刪除。
[root@hadoop code]# java org.zk.ListGroup localhost zoo
2014-10-30 03:23:41,120 [myid:] - INFO [main:Environment@100] - Client environment:……
……
duck
cow
對於參與到一個分佈式系統中的節點,這樣就有了一個創建節點列表的方法。這些節點也許彼此並不瞭解。例如,一個想使用列表中節點來完成某些工做的客戶端,可以在這些節點不知道客戶端的狀況下發現它們。最後,注意,組成員關係管理並不能解決與節點通訊過程當中出現的網絡問題。即便一個節點是一個組中的成員,在與其通訊的過程當中仍然會出現故障,這種故障必須以一種合適的方式解決(重試、使用組中另一個成員等)。☆☆☆
3.4 ZooKeeper命令行工具
ZooKeeper提供了一個命令行工具用於在其命名空間內進行交互。咱們可使用這個命令工具列出/zoo節點之下的znode列表,以下所示
[root@hadoop code]# zkCli.sh -server localhost ls /zoo
Connecting to localhost
……
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[duck, cow]
[root@hadoop code]#
3.5 刪除組
下面來看如何刪除一個組。ZooKeeper類提供了一個delete()方法,該方法有兩個參數:
1. 路徑
2. 版本號
若是所提供的版本號與znode的版本號一致,ZooKeeper會刪除這個znode。這是一種樂觀的加鎖機制,使客戶端可以檢測出對znode的修改衝突。經過將版本號設置爲-1,能夠繞過這個版本檢測機制,無論znode的版本號是什麼而直接將其刪除。ZooKeeper不支持遞歸的刪除操做,所以在刪除父節點以前必須先刪除子節點。
在代碼3.5中,DeleteGroup類用於刪除一個組及其全部成員。
代碼3.5用於刪除一個組及其全部成員的程序
package org.zk; import java.io.IOException; import java.util.List; import org.apache.zookeeper.KeeperException; public class DeleteGroup extends ConnectionWatcher{ public void delete(String groupName) throws InterruptedException, KeeperException{ String path="/"+groupName; List<String> children; try { children = zk.getChildren(path, false); for(String child:children){ zk.delete(path+"/"+child, -1); } zk.delete(path, -1); } catch (KeeperException.NoNodeException e) { System.out.printf("Group %s does not exist\n", groupName); System.exit(1); } } public static void main(String[] args) throws InterruptedException, IOException, KeeperException { DeleteGroup deleteGroup = new DeleteGroup(); deleteGroup.connect(args[0]); deleteGroup.delete(args[1]); deleteGroup.close(); } }
最後,咱們能夠刪除以前所建立的zoo組:
[root@hadoop code]# java org.zk.DeleteGroup localhost zoo……[root@hadoop code]# java org.zk.ListGroup localhost zoo2014-10-30 05:39:41,974 [myid:] - INFO [main:Environment@100] - Client environment:……Group zoo does not exist[root@hadoop code]#