先給一堆學習文檔,方便以后查看
官網文檔地址大全:
OverView(概述)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperOver.html
Getting Started(開始入門)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperStarted.html
Tutorial(教程)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperTutorial.html
Java Example(Java示例)
http://zookeeper.apache.org/doc/r3.4.6/javaExample.html
Programmer's Guide(開發人員指南)
http://zookeeper.apache.org/doc/r3.4.6/zookeeperProgrammers.html
Recipes and Solutions(技巧及解決方案)
http://zookeeper.apache.org/doc/r3.4.6/recipes.html
3.4.6 API online(在線API速查)
http://zookeeper.apache.org/doc/r3.4.6/api/index.html
另外推薦園友sunddenly的zookeeper系列
http://www.cnblogs.com/sunddenly/category/620563.html
一、安裝部署
本文在一台機器上模擬3個 zk server的集群安裝
1.1 下載解壓
解壓到3個目錄(模擬3台zk server):
/home/hadoop/zookeeper-1 /home/hadoop/zookeeper-2 /home/hadoop/zookeeper-3
1.2 創建每個目錄下conf/zoo.cfg配置文件
/home/hadoop/zookeeper-1/conf/zoo.cfg 內容如下:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/hadoop/tmp/zk1/data dataLogDir=/home/hadoop/tmp/zk1/log clientPort=2181 server.1=localhost:2287:3387 server.2=localhost:2288:3388 server.3=localhost:2289:3389
/home/hadoop/zookeeper-2/conf/zoo.cfg 內容如下:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/hadoop/tmp/zk2/data dataLogDir=/home/hadoop/tmp/zk2/log clientPort=2182 server.1=localhost:2287:3387 server.2=localhost:2288:3388 server.3=localhost:2289:3389
/home/hadoop/zookeeper-3/conf/zoo.cfg 內容如下:
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/hadoop/tmp/zk3/data dataLogDir=/home/hadoop/tmp/zk3/log clientPort=2183 server.1=localhost:2287:3387 server.2=localhost:2288:3388 server.3=localhost:2289:3389
注:因為是在一台機器上模擬集群,所以端口不能重復,這里用2181~2183,2287~2289,以及3387~3389相互錯開。另外每個zk的instance,都需要設置獨立的數據存儲目錄、日志存儲目錄,所以dataDir、dataLogDir這二個節點對應的目錄,需要手動先創建好。
另外還有一個灰常關鍵的設置,在每個zk server配置文件的dataDir所對應的目錄下,必須創建一個名為myid的文件,其中的內容必須與zoo.cfg中server.x 中的x相同,即:
/home/hadoop/tmp/zk1/data/myid 中的內容為1,對應server.1中的1
/home/hadoop/tmp/zk2/data/myid 中的內容為2,對應server.2中的2
/home/hadoop/tmp/zk3/data/myid 中的內容為3,對應server.3中的3
生產環境中,分布式集群部署的步驟與上面基本相同,只不過因為各zk server分布在不同的機器,上述配置文件中的localhost換成各服務器的真實Ip即可。分布在不同的機器后,不存在端口沖突問題,可以讓每個服務器的zk均采用相同的端口,這樣管理起來比較方便。
1.3 啟動驗證
/home/hadoop/zookeeper-1/bin/zkServer.sh start /home/hadoop/zookeeper-2/bin/zkServer.sh start /home/hadoop/zookeeper-3/bin/zkServer.sh start
啟用成功后,輸入 jps 看下進程
20351 ZooKeeperMain
20791 QuorumPeerMain
20822 QuorumPeerMain
20865 QuorumPeerMain
應該至少能看到以上幾個進程。
可以啟動客戶端測試下:
bin/zkCli.sh -server localhost:2181
(注:如果是遠程連接,把localhost換成指定的IP即可)
成功后,應該會進到提示符下,類似下面這樣:
[zk: localhost:2181(CONNECTED) 0]
然后,就可以用一些基礎命令,比如 ls ,create ,delete ,get 來測試了(關於這些命令,大家可以查看文檔),特別提一個很有用的命令rmr 用來遞歸刪除某個節點及其所有子節點
二、java 與 zk的連接示例
2.1 maven項目的pom.xml中先添加以下依賴項
<!--zk--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.6</version> </dependency>
2.2 最基本的示例程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package
yjmyzz;
import
java.io.IOException;
import
org.apache.zookeeper.*;
import
org.apache.zookeeper.data.Stat;
public
class
ZooKeeperHello {
public
static
void
main(String[] args)
throws
IOException, InterruptedException, KeeperException {
ZooKeeper zk =
new
ZooKeeper(
"172.28.20.102:2181"
,
300000
,
new
DemoWatcher());
//連接zk server
String node =
"/app1"
;
Stat stat = zk.exists(node,
false
);
//檢測/app1是否存在
if
(stat ==
null
) {
//創建節點
String createResult = zk.create(node,
"test"
.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(createResult);
}
//獲取節點的值
byte
[] b = zk.getData(node,
false
, stat);
System.out.println(
new
String(b));
zk.close();
}
static
class
DemoWatcher
implements
Watcher {
@Override
public
void
process(WatchedEvent event) {
System.out.println(
"----------->"
);
System.out.println(
"path:"
+ event.getPath());
System.out.println(
"type:"
+ event.getType());
System.out.println(
"stat:"
+ event.getState());
System.out.println(
"<-----------"
);
}
}
}
|
2.3 與zk集群的連接
zk的優點之一,就是高可用性,上面的代碼連接的是單台zk server,如果這台server掛了,自然代碼就會出錯,事實上zk的API考慮到了這一點,把連接代碼改成下面這樣:
ZooKeeper zk = new ZooKeeper("172.28.20.102:2181,172.28.20.102:2182,172.28.20.102:2183", 300000, new DemoWatcher());//連接zk server
即:IP1:port1,IP2:port2,IP3:port3... 用這種方式連接集群就行了,只要有超過半數的zk server還活着,應用一般就沒問題。但是也有一種極罕見的情況,比如這行代碼執行時,剛初始化完成,正准備連接ip1時,因為網絡故障ip1對應的server掛了,仍然會報錯(此時,zk還來不及選出新leader),這個問題詳見:http://segmentfault.com/q/1010000002506725/a-1020000002507402,參考該文的做法,改成:
1 ZooKeeper zk = new ZooKeeper("172.28.20.102:2181,172.28.20.102:2182,172.28.20.102:2183", 300000, new DemoWatcher());//連接zk server 2 if (!zk.getState().equals(ZooKeeper.States.CONNECTED)) { 3 while (true) { 4 if (zk.getState().equals(ZooKeeper.States.CONNECTED)) { 5 break; 6 } 7 try { 8 TimeUnit.SECONDS.sleep(5); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 } 13 }
但是這樣代碼未免太冗長,建議用開源的zkClient,官方地址: https://github.com/sgroschupf/zkclient,使用方法很簡單:
<!--zkclient--> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency>
pom.xml先加這一坨,然后這樣用:
1 @Test 2 public void testZkClient() { 3 ZkClient zkClient = new ZkClient("172.28.20.102:2181,172.28.20.102:2182,172.28.20.102:2183"); 4 String node = "/app2"; 5 if (!zkClient.exists(node)) { 6 zkClient.createPersistent(node, "hello zk"); 7 } 8 System.out.println(zkClient.readData(node)); 9 }