文章目錄
1 ZK的原生API
1.1 java操作原生API
1.1.1 引入依賴
使用java
操作zookeeper
,引入maven
座標
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.5</version>
</dependency>
1.1.2 創建會話
創建會話方法:客戶端通過創建一個zookeeper
實例來鏈接zookeeper
服務器
Zookeeper
提供了4
個構造方法,根據所提供的參數不同
參數說明如下:
connectString:
連接服務器列表,如果有多個則用,
分隔sessionTimeout:
心跳檢測時間週期(毫秒
)wather:
事件處理通知器canBeReadOnly:
標識當前會話是否支持只讀sessionId和sessionPassword:
提供連接zookeeper
的session
和密碼,通過這兩個確定唯一一臺客戶端,目的可以提供重複會話
注意
:zookeeper
客戶端和服務器端會話的建立是一個異步過程
,也就是說在程序中,我們程序方法在處理完客戶端初始化後立即返回(也就是說程序往下執行代碼,這樣,大多數情況下我們並沒有真正構建一個可用會話,在會話的生命週期處於CONNECTING
時纔算真正建立完畢,所以我們需要使用多線程中學習的一個小工具類)
public class ZooKeeperDemo{
//zk 連接地址
private static final String CONNECT_ADDR="192.168.126.130:2181";
//session 超時時間
private static final Integer SESSION_OUTTIME=5000;
//阻塞程序執行,用於等待zookeeper連接成功,發送成功信號
private static CountDownLatch countDown = new CountDownLatch(1);
public static void main(String[] args) throws Exception{
//zk 連接
ZooKeeper zk = new ZooKeeper(CONNECT_ADDR,SESSION_OUTTIME,new Watcher(){
@Override
public void process(WatchedEvent event){
Event.KeeperState state = event.getState();
Event.EventType type = event.getType();
//如果建立了安全連接
if(Event.KeeperState.SyncConnected==state){
if(Event.EventType.None==type){
//如果連接建立成功,則發送信號
countDown.countDown();
System.out.println("zk 建立連接");
}
}
}
});
//進行阻塞
countDown.await();
System.out.println("zk 執行了");
//關閉會話
zk.close();
}
}
1.1.3 節點的CRUD
1.1.3.1 創建節點
創建節點方法:create
有兩種創建節點的方法:同步
和異步
創建節點方式
同步方式:
- 參數1,節點路徑(名稱):
/nodeName
(不允許遞歸創建節點
,也就是說在父節點不存在的情況下,不允許創建子節點) - 參數2,節點內容: 要求類型是
字節數組
- 參數3,節點權限:使用
Ids.OPEN_ACL_UNSAFE
開發權限即可。(這個參數一般在權限沒有太高要求的場景下,沒必要關注) - 參數4,節點類型:創建節點的類型:
CreateMode.*
,提供以下幾種節點類型:
PERSISENT
:持久節點
PERSISENT_SEQUENTIAL
:持久順序節點
EPHEMERAL
:臨時節點
EPHEMERAL_SEQUENTIAL
:臨時順序節點
CONTAINER
:容器節點,用於Leader
、Lock
等特殊用途,當容器節點不存在任何子節點時,容器將成爲服務器在將來某個時候刪除的候選節點
PERSISTENT_WITH_TTL
:帶TTL
(time-to-live
,存活時間)的永久節點,節點在TTL
時間之內沒有得到更新並且沒有孩子節點,就會被自動刪除
PERSISTENT_SEQUENTIAL_WITH_TTL
:帶TTL
(time-to-live
,存活時間)和單調遞增序號的永久節點,節點在TTL
時間之內沒有得到更新並且沒有孩子節點,就會被自動刪除
//創建父節點,此處的zk是上一步的會話產生的
String ret = zk.create("/testRoot","testRoot".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISENT);
System.out.println(ret);
注意
:臨時節點效率很高,主要用來作爲分佈式鎖
異步方式:(在同步方式參數基礎上增加倆參數)
- 參數5,註冊一個異步回調函數,要實現
AsynCallBack.VoidCallBack
接口,重寫processResult(int rc,String path,Obejct ctx,String name)
方法,當節點創建完畢後執行此方法
rc
:爲服務端響應碼,0
表示調用成功,-4表示端口連接,-110
表示指定節點存在,-112
表示會話已經過期
path
:接口調用時傳入API
的數據節點的路徑參數
ctx
:爲調用接口傳入API
的ctx
的值
name
:實際在服務器端創建節點的名稱 - 參數6,傳遞給回調函數的參數,一般爲上下文(
context
)信息
//此處的 -1是跳過版本限制 dataVersion ,在刪除時如果傳入的版本號不是-1 與現有版本號一致,那麼可以刪除
zk.delete("/testRoot",-1,new AsynCallBack.VoidCallBack(){
@Override
public void processResult(int rc,String path,Object ctx){
System.out.println(rc);
System.out.println(path);
System.out.println(ctx);
}
},"a");
1.1.3.2 修改節點
//此處的-1 也是跳過版本號的檢查
zk.setData("/testRoot","modify data root".getBytes(),-1);
1.1.3.3 判斷是否存在
判斷節點是否存在
// 參數一:路徑,參數二:是否watch監聽
zk.exists("/testRoot",false);
1.1.3.4 獲取節點值
byte[] data = zk.getData("/testRoot", false, null);
System.out.println(new String(data));
System.out.println(zk.getChildren("/testRoot", false));
1.1.3.5 刪除節點
//刪除節點
zk.delete("/testRoot/children", -1);
System.out.println(zk.exists("/testRoot/children", false));
2 zkClient的API
2.1 引入pom依賴
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
2.2 操作客戶端
2.2.1 創建客戶端
/** zookeeper地址 */
static final String CONNECT_ADDR = "192.168.1.171:2181,192.168.1.172:2181,192.168.1.173:2181";
/** session超時時間 */
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), 5000);
}
2.2.2 增加和刪除節點
可以遞歸
增加和刪除節點
創建節點時,那個true
是否創建父節點
//1. create and delete方法
zkc.createEphemeral("/temp");
//第二個參數createParents==true,表示父節點不存在時創建父節點(遞歸創建)
zkc.createPersistent("/super/c1", true);
Thread.sleep(10000);
zkc.delete("/temp");
zkc.deleteRecursive("/super");
2.2.3 讀取節點
//2. 設置path和data 並且讀取子節點和每個節點的內容
zkc.createPersistent("/super", "1234");
zkc.createPersistent("/super/c1", "c1內容");
zkc.createPersistent("/super/c2", "c2內容");
List<String> list = zkc.getChildren("/super");
for(String p : list){
System.out.println(p);
String rp = "/super/" + p;
//此處的readData是原生API
String data = zkc.readData(rp);
System.out.println("節點爲:" + rp + ",內容爲: " + data);
}
2.2.4 判斷是否存在
//3. 更新和判斷節點是否存在
zkc.writeData("/super/c1", "新內容");
System.out.println(zkc.readData("/super/c1"));
System.out.println(zkc.exists("/super/c1"));
2.3 zkClinet不需要watcher
zkClient
不用watcher
和watcher
參數,也就是說我們開發人員無需關心反覆註冊Watcher
的問題,zkclient
給我們提供了一套監聽方式,可以使用監聽節點的方式進行操作,剔除了繁瑣的反覆watcher
操作,簡化了代碼的複雜程度
2.3.1 subscribeChildChanges方法
只監聽父子節點的新增和刪除,但是節點變化不監聽
- 參數一:
path
路徑 - 參數二:實現了
IZkChildListener
接口的類
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), 5000);
//對父節點添加監聽子節點變化。
zkc.subscribeChildChanges("/super", new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println("parentPath: " + parentPath);
System.out.println("currentChilds: " + currentChilds);
}
});
Thread.sleep(3000);
zkc.createPersistent("/super");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c1", "c1內容");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c2", "c2內容");
Thread.sleep(1000);
zkc.delete("/super/c2");
Thread.sleep(1000);
zkc.deleteRecursive("/super");
Thread.sleep(Integer.MAX_VALUE);
}
2.3.2 subscribeDataChanges方法
主要監聽節點的刪除和改變
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), 5000);
zkc.createPersistent("/super", "1234");
//對父節點添加監聽子節點變化。
zkc.subscribeDataChanges("/super", new IZkDataListener() {
@Override
public void handleDataDeleted(String path) throws Exception {
System.out.println("刪除的節點爲:" + path);
}
@Override
public void handleDataChange(String path, Object data) throws Exception {
System.out.println("變更的節點爲:" + path + ", 變更內容爲:" + data);
}
});
Thread.sleep(3000);
zkc.writeData("/super", "456", -1);
Thread.sleep(1000);
zkc.delete("/super");
Thread.sleep(Integer.MAX_VALUE);
}