ZooKeeper系列(三)
前面雖然配置了叢集模式的Zookeeper
,但是為了方面學建議在偽分散式模式的Zookeeper
學習Zookeeper
的shell命令。
一、Zookeeper
的四字命令
Zookeeper
支援某些特定的四字命令字母與其的互動。他們大多數是查詢命令,用來獲取Zookeeper
服務的當前狀態及相關資訊。使用者在客戶端可以通過telnet
或nc
向Zookeeper
提交相應的命令。Zookeeper
常用的四字命令見圖1.1所示。
圖 1.1
圖1.2是Zookeeper
四字命令的一個簡單用例。
[[email protected] ~]# echo ruok|nc localhost 2181
[[email protected] ~]# zkServer.sh start zoo1.cfg
JMX enabled by default
Using config: /usr/local/zk/bin/../conf/zoo1.cfg
Starting Zookeeper ... STARTED
[[email protected] ~]# zkServer.sh start zoo2.cfg
JMX enabled by default
Using config: /usr/local/zk/bin/../conf/zoo2.cfg
Starting Zookeeper ... STARTED
[ [email protected] ~]# zkServer.sh start zoo3.cfg
JMX enabled by default
Using config: /usr/local/zk/bin/../conf/zoo3.cfg
Starting Zookeeper ... STARTED
[[email protected] ~]# echo ruok|nc localhost 2181
imok[[email protected] ~]# echo ruok|nc localhost 2182
imok[[email protected] ~]# echo ruok|nc localhost 2183
imok[[email protected] ~]# 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
[[email protected] ~]#
二、Zookeeper
的簡單操作
2.1 Zookeeper
的shell操作
2.1.1 Zookeeper
命令工具
再啟動Zookeeper
服務之後,輸入以下命令,連線到Zookeeper
服務:
zkCli.sh -server localhost:2181
執行結果如下所示:
[[email protected] ~]# zkCli.sh -server localhost:2181
Connecting to localhost:2181
2014-10-17 03:35:51,051 [myid:] - INFO [main:[email protected]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:[email protected]100] - Client environment:host.name=hadoop
2014-10-17 03:35:51,057 [myid:] - INFO [main:[email protected]100] - Client environment:java.version=1.6.0_24
2014-10-17 03:35:51,057 [myid:] - INFO [main:[email protected]100] - Client environment:java.vendor=Sun Microsystems Inc.
2014-10-17 03:35:51,066 [myid:] - INFO [main:[email protected]100] - Client environment:java.home=/usr/local/jdk/jre
2014-10-17 03:35:51,079 [myid:] - INFO [main:[email protected]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:[email protected]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:[email protected]100] - Client environment:java.io.tmpdir=/tmp
2014-10-17 03:35:51,086 [myid:] - INFO [main:[email protected]100] - Client environment:java.compiler=<NA>
2014-10-17 03:35:51,099 [myid:] - INFO [main:[email protected]100] - Client environment:os.name=Linux
2014-10-17 03:35:51,100 [myid:] - INFO [main:[email protected]100] - Client environment:os.arch=i386
2014-10-17 03:35:51,101 [myid:] - INFO [main:[email protected]100] - Client environment:os.version=2.6.32-358.el6.i686
2014-10-17 03:35:51,101 [myid:] - INFO [main:[email protected]100] - Client environment:user.name=root
2014-10-17 03:35:51,102 [myid:] - INFO [main:[email protected]100] - Client environment:user.home=/root
2014-10-17 03:35:51,106 [myid:] - INFO [main:[email protected]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`.`Zookeeper`[email protected]
Welcome to `Zookeeper`!
JLine support is enabled
2014-10-17 03:35:51,233 [myid:] - INFO [main-SendThread(localhost:2181):[email protected]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):[email protected]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):[email protected]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
命令,如圖2.1所示。
圖 2.1
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 myData
[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
(4)接下來通過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
(5)再次使用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
(6)下面我們將剛才建立的Znode
刪除,執行命令:delete /zk
[zk: localhost:2181(CONNECTED) 7] delete /zk
(7)最後再次使用ls
命令檢視Zookeeper
中的內容,執行命令:ls /
[zk: localhost:2181(CONNECTED) 8] ls /
[Zookeeper]
經過驗證,zk
節點已經刪除。
2.2 Zookeeper
的api的簡單使用
2.2.1 Zookeeper
API簡介
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.2
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 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.在建立節點的時候,需要提供節點的名稱、資料、許可權以及節點型別。此外,使用 exists
函式時,如果節點不存在將返回一個 null
值。
2.關於 Zookeeper
API 的更多詳細資訊,讀者可以檢視 Zookeeper
的 API 文件,如下所示:
程式碼的執行結果如下:
- 建立
Zookeeper
節點(Znode:/znode
;資料:myData2
;許可權:OPEN_ACL_UNSAFE
;節點型別:Persistent
)
None - 檢視節點是否建立成功:
/znode myData2
- 修改節點資料:
- 檢視是否修改成功:
jiang1234
- 刪除節點:
- 檢視
/znode
節點狀態:
節點間狀態:[null]
三、Zookeeper
示例
假設一組伺服器,用於為客戶端提供一些服務。我們希望每個客戶端都能夠能夠找到其中一臺伺服器,使其能夠使用這些服務,挑戰之一就是維護這組伺服器列表。這組伺服器的成員列表明顯不能存在網路中的單個節點上,因為如果那個節點發生故障,就意味著是整個系統的故障(我們希望這個列表有很高的可用性)。假設我們有了一個可靠的方法解決了這個成員列表的儲存問題。如果其中一臺伺服器出現故障,我們仍然需要解決如何從伺服器成員列表中將它刪除的問題。某個程序需要負責刪除故障伺服器,但注意不能由故障伺服器自己來完成,因為故障伺服器已經不再執行。
我們所描述的不是一個被動的分散式資料結構,而是一個主動的、能夠在某個外部事件發生時修改資料項狀態的資料結構。Zookeeper
提供這種服務,所以讓我們看看如何使用它來實現這種眾所周知的組成員管理應用。
Zookeeper
中的組成員關係
理解Zookeeper
的一種方法就是將其看作一個具有高可用性的檔案系統。但這個檔案系統中沒有檔案和目錄,而是統一使用“節點”(node
)的概念,稱為znode
。znode
既可以作為儲存資料的容器(如同檔案),也可以作為儲存其他znode的容器(如同目錄)。所有的znode
構成一個層次化的名稱空間。一種自然的建立組成員列表的方式就是利用這種層次結構,建立一個以組名為節點名的znode
作為父節點,然後以組成員名(伺服器名)為節點名來建立作為子節點的znode
。如下圖給出了一組具有層次結構的znode
。
圖 Zookeeper
中的znode
在這個示例中,我們沒有在任何znode
中儲存資料,但在一個真實的應用中,你可以將“關於成員的資料”儲存在它們的znode
中,例如主機名。
3.1 建立組
3.1.1 程式碼示例
讓我們通過編寫一段程式的方式來再次詳細介紹Zookeeper
的Java API,這段示例程式用於為組名為/zoo
的組建立一個znode
。程式碼參見程式碼3.1:
程式碼 3.1 該程式在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();
}
}
執行後的結果為:
[[email protected] code]# ls
build classes CreateGroup.java HelloWorld.java jar.jar PackageTest.java Zookeeper.out
[[email protected] code]# javac -d ./classes CreateGroup.java
[[email protected] 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
[[email protected] 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
來代表一個組成員。
程式碼3.2 中的程式JoinGroup
實現了這個想法。在基類ConnectionWatcher
中,對建立和連線Zookeeper
例項的程式邏輯進行了重構,參見程式碼3.2。
程式碼 3.2 用於將成員加入組的程式
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 列出組成員
現在,我們需要一段程式來檢視組成員,參見程式碼3.4。
程式碼 3.4 用於列出組成員的程式
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 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
資料夾,用於存放生成位元組碼檔案:
[[email protected] ~]# cd /usr/code
[[email protected] code]# ls
ConnectionWatcher.java DeleteGroup.java ListGroup.java
classes CreateGroup.java JoinGroup.java PackageTest.java
[[email protected] code]# javac -d ./classes ConnectionWatcher.java
[[email protected] code]# javac -d ./classes *.java
由於目前我們還沒有在組中新增任何成員,因此zoo
是空的:
[[email protected] code]# java org.zk.ListGroup localhost zoo
2014-10-30 01:52:19,703 [myid:] - INFO [main:[email protected]] - 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,以便能夠在檢視組成員之後殺死程序。
[[email protected] code]#
2014-10-30 03:15:30,619 [myid:] - INFO [main:[email protected]] - 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 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]
相關推薦
ZooKeeper系列(三)
前面雖然配置了叢集模式的Zookeeper,但是為了方面學建議在偽分散式模式的Zookeeper學習Zookeeper的shell命令。
一、Zookeeper的四字命令
Zookeeper支援某些特定的四字命令字母與其的互動。他們大多數是查詢命令,用來
ZooKeeper系列(三)—— Zookeeper 常用 Shell 命令
一、節點增刪改查
1.1 啟動服務和連線服務
# 啟動服務
bin/zkServer.sh start
#連線服務 不指定服務地址則預設連線到localhost:2181
zkCli.sh -server hadoop001:2181
1.2 help命令
使用 help 可以檢視所有命令及格式。
1.3
zookeeper學習系列(三)zookeeper基本原理
ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,它包含一個簡單的原語集,分散式應用程式可以基於它實現同步服務,配置維護和命名服務等。Zookeeper是hadoop的一個子專案。在分散式應用中,由於工程師不能很好地使用鎖機制,以及基於訊息的協調機制
分布式緩存技術redis學習系列(三)——redis高級應用(主從、事務與鎖、持久化)
master ica not ood www working can 出了 owin 上文《詳細講解redis數據結構(內存模型)以及常用命令》介紹了redis的數據類型以及常用命令,本文我們來學習下redis的一些高級特性。
回到頂部
安全性設置
設置客戶端操作秘密
數據結構系列(三)線性表
復雜 -o -type 復雜度 順序結構 之前 包含 替換 鏈式存儲結構 線性表是什麽
零個或多個數據元素的有序序列
線性存儲結構
例如
java中的數組,每次都申請固定長度內存空間,並且長度不可變
而arraylist則是長度可變的數組,這是java在底層對數組
【原創】源碼角度分析Android的消息機制系列(三)——ThreadLocal的工作原理
沒有 cit gen 管理 pre 靜態 bsp 允許 clas ι 版權聲明:本文為博主原創文章,未經博主允許不得轉載。
先看Android源碼(API24)中對ThreadLocal的定義:
public class ThreadLocal<T>
源碼分析系列(三)x264_deblocking_dataflow
像素 色度 結構 inf blank 水平 frame 垂直 左右 http://www.cnblogs.com/xkfz007/articles/2616157.html
去塊濾波(Deblocking)部分關鍵函數
3.1 deblocking_filter_ed
Windows Server 2012 AD 站點和域部署系列(三)創建站點、子網及鏈接
子網 站點 windows server 2012 配置域 本章博文開始在根域ds01 端創建BJ、SH、GZ站點 ,配置子網及相關站點間的鏈接 。創建站點:1、重命名默認站點:登陸ds01,打開“Active Directory 站點和服務”,右鍵點擊默認的站點Default-First-Sit
PHP系列(三)PHP數組與數據結構
php數組與數據結構 PHP數組與數據結構數組是把若幹變量按有序的形式組織起來的一種形式。這些數據元素的集數組分為一維二維三維、索引數組(數組索引是整數)和關聯數組 (1)數組的聲明1、一個數組中存的多個內容、數組中的內容叫作“元素”2、每個元素都是由健和值組成的Key/
Linux系統運維常見面試簡答題系列(三)(9題)
connect 切換 -a ip) 整理 程序 strong ack 自己 1. 寫一個sed命令,修改/tmp/input.txt文件的內容,要求:(1) 刪除所有空行;(2) 一行中,如果包含”11111″,則在”11111″前面插入”AAA”,在”11111″後面插入
Python操作rabbitmq系列(三):多個接收端消費消息
name 連接 logs http clas header 消費者 exclusive pub 接著上一章。這一章,我們要將同一個消息發給多個客戶端。這就是發布訂閱模式。直接看代碼:
發送端:
import pikaimport sysconnection = pika.B
Flask 學習系列(三)---Jinjia2使用過濾器
ide 數位 指定字段 模板 小數 else capital 12px 效果圖 再Jinjia2中過濾器是一種轉變變量輸出內容的技術。··過濾器通過管道符號“|與變量鏈接,並且可以通過圓括號傳遞參數” 。舉例說明:
{{my_variable|default(‘my_var
ZooKeeper入門(三) ZooKeeper數據模型
每次 con ges 可用 同文件 2.3 per 而是 創建時間 1 簡述
ZooKeeper可以看成一種高可用性的文件系統,但是,它沒有文件和目錄,而是使用節點,稱為znode。
znode可以作為保存數據的容器(如同文件),也可以作為保存其他節點的容器(如同目錄)。
Docker系列(三)容器管理
mozilla http 格式 file tor centos determine dia 進程 3.1 新建容器並啟動所需要的命令主要為docker run
[root@localhost ~]# docker run centos /bin/echo "syavi
wifi認證Portal開發系列(三):portal協議
tro spa size http log ron 認證 gin auto 中國移動WLAN業務PORTAL協議規範介紹
wifi認證Portal開發系列(三):portal協議
詳解YUV系列(三)----YUV420
roc 根據 系列 watermark 存儲方式 圖片 images src fff 前兩講詳細講解了YUV444以及YUV422兩種格式,實際中這兩種格式使用的相對較少,使用比較多的便是本節要梳理的YUV420格式嘍,同樣,老辦法,老套路嘍。
一、文字描述:YUV
C# 多線程系列(三)
job row 空閑 最好 方式 不同的 運行時 作業 tun 線程池
創建線程需要時間,如果有不同的小任務要完成,就可以事先創建許多線程,在應完成這些任務時發出請求。這個線程數最好在需要更多線程時增加,在需要釋放資源時減少。
不需要自己創建這樣的一個列表。該列表由T
Docker入門與應用系列(三)容器管理
輸出 clear tag 程序 ipaddr one 停止 1.2 標準 一、啟動容器
啟動容器有兩種方式,一種是基於鏡像新建一個容器並啟動,另一個是將終止狀態的容器重新啟動。
1.1 新建並啟動
主要命令為 docker run
下面的命令輸出一個&rd
Java Thread系列(三)線程安全
AI 資源 習慣 get string tar rup end 就是 Java Thread系列(三)線程安全
一、什麽是線程安全
線程安全概念:當多個線程訪問某一個類(對象或方法)時,這個類始終都能表現出正確的行為,那麽這個類(對象或方法)就是線程安全的。
線程安全來
Greeplum 系列(三) 基本用法
ont price createdb version access tex sin 方便 清空表 Greeplum 系列(三) 基本用法
《PostgreSQL 教程》:https://www.yiibai.com/postgresql
一、Greeplum 登陸與創建