zookeeper事件監聽機制
- watcher機制:
zookeeper提供了數據的發佈/訂閱功能,多個訂閱者可同時監聽某一特定主題對象,當該主題對象的自身狀態發生變化時(例如節點內容改變、節點下的子節點列表改變 等),會實時、主動通知所有訂閱者
zookeeper採用了Watcher機制實現數據的發佈/訂閱功能。該機制在被訂閱對象發生變化時會異步通知客戶端,因此客戶端不必在Watcher註冊後輪詢阻塞,從而減輕了客戶端壓力
-
watcher模型:
客戶端首先將watcher註冊到zk服務端,同時將watcher對象保存在客戶端的watcher管理器中,zk的服務端監聽到數據的變化後,通知客戶端,客戶端的watcher管理器觸發相關的watcher來回調來處理邏輯,完成整體的發佈/訂閱流程
-
watcher特性
-
一次性
watcher是一次性的,一旦被觸發就會移除,再次使用時需要重新註冊
-
輕量級
WatchEvent是最小的通信單元,結構上只包含通知狀態、事件類型和節點 路徑,並不會告訴數據節點變化前後的具體內容;
-
客戶端順序回調
watcher回調是順序串行化執行的,只有回調後客戶端才能看到最新的數 據狀態。一個watcher回調邏輯不應該太多,以免影響別的watcher執行
-
時效性
watcher只有在當前session徹底失效時纔會無效,若在session有效期內快速重連成功,則watcher依然存在,仍可接收到通知
-
-
watcher接口
Watcher是一個接口,任何實現了Watcher接口的類就是一個新的Watcher。
Watcher內部包含了兩個枚舉類:KeeperState、EventType
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-M8yCiNSs-1585660091783)(E:/Typora/typora-user-images/18300896-0cf1d1fd914f0a1e.webp)]
- Watcher通知狀態**(KeeperState)**
KeeperState是客戶端與服務端連接狀態發生變化時對應的通知類型
枚舉屬性 | 說明 |
---|---|
SyncConnected | 客戶端與服務器正常連接時 |
Disconnected | 客戶端與服務器斷開連接時 |
Expired | 會話session失效時 |
AuthFailed | 身份認證失敗時 |
- Watcher事件類型**(EventType)**
EventType是數據節點(znode)發生變化時對應的通知類型
EventType變化時,KeeperState永遠處於SyncConnected通知狀態下;當KeeperState發生變化時, EventType永遠爲None。
枚舉屬性 | 說明 |
---|---|
None | 無 |
NodeCreated | Watcher監聽的數據節點被創建時 |
NodeDeleted | Watcher監聽的數據節點被刪除時 |
NodeDataChanged | Watcher監聽的數據節點內容發生變更時(無論內容數據是否變化) |
NodeChildrenChanged | Watcher監聽的數據節點的子節點列表發生變更時 |
客戶端接收到的相關事件通知中只包含狀態及類型等信息,不包括節點變化前後的具體內容,變化前的數據需業務自身存儲,變化後的數據需調用get等方法重新獲取
- 捕獲相應的事件
在zookeeper中採用
zk.exists(path, watch),zk.getData(path, watcher, stat) ,zk.getChildren(path, watch)
這樣的方式爲某個znode註冊監聽
註冊方式 | created | childrenchanged | changed | delete |
---|---|---|---|---|
zk.exists(path, watch) | 可監控 | 可監控 | 可監控 | |
zk.getData(path, watcher, stat) | 可監控 | 可監控 | ||
zk.getChildren(path, watch) | 可監控 | 可監控 |
- 客戶端和服務端連接狀態實現demo
/**
* @Author: zxx
* @Date: 2020/3/29 22:05
* @Description: watcher機制
* 通知狀態 KeeperState:
* SyncConnected:客戶端與服務器正常連接時
* Disconnected:客戶端與服務器斷開連接時
* Expired:會話session失效時
* AuthFailed:身份認證失敗時
*
* 事件類型 EventType none
*/
public class ZKConnectWatcher implements Watcher {
// 計數器對象
public static CountDownLatch countDownLatch=new CountDownLatch(1);
// 連接對象
public static ZooKeeper zooKeeper;
public void process(WatchedEvent watchedEvent) {
try {
//EventType = None時
if (watchedEvent.getType() == Event.EventType.None){
if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
System.out.println("連接成功");
countDownLatch.countDown();
}else if (watchedEvent.getState() == Event.KeeperState.Disconnected){
System.out.println("斷開連接");
}else if (watchedEvent.getState() == Event.KeeperState.Expired){
System.out.println("會話超時");
}else if (watchedEvent.getState() == Event.KeeperState.AuthFailed){
System.out.println("認證失敗");
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
zooKeeper=new ZooKeeper("192.168.21.141:2181", 5000, new ZKConnectWatcher());
// 阻塞線程等待連接的創建
countDownLatch.await();
// 會話id
System.out.println(zooKeeper.getSessionId());
Thread.sleep(50000);
zooKeeper.close();
System.out.println("結束");
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 檢查節點是否存在
/**
* @Author: zxx
* @Date: 2020/3/30 19:57
* @Description: zk.exists(“/node- x”,watcher)
*/
public class ZKWatcherExists {
private String IP = "192.168.60.130:2181";
public static ZooKeeper zooKeeper;
//連接zookeeper
@Before
public void before() throws InterruptedException, IOException {
final CountDownLatch countDownLatch=new CountDownLatch(1);
zooKeeper = new ZooKeeper(IP, 6000, new Watcher() {
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
countDownLatch.await();
}
@After
public void after() throws InterruptedException {
zooKeeper.close();
}
@Test
public void watcherExists1() throws KeeperException, InterruptedException {
// arg1:節點的路徑
// arg2:使用連接對象中的watcher
zooKeeper.exists("/watcher1", true);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherExists2() throws KeeperException, InterruptedException {
Watcher watcher = new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}};
zooKeeper.exists("/watcher1", watcher);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherExists3() throws KeeperException, InterruptedException {
// arg1:節點的路徑
// arg2:使用連接對象中的watcher
zooKeeper.exists("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherExists4() throws KeeperException, InterruptedException {
zooKeeper.exists("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher1");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
zooKeeper.exists("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher2");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
Thread.sleep(50000);
System.out.println("結束");
}
}
- 查看節點
/**
* @Author: zxx
* @Date: 2020/3/30 19:57
* @Description: zk.getData(path, watcher, stat)
*/
public class ZKWatcherGetData {
private String IP = "192.168.60.130:2181";
public static ZooKeeper zooKeeper;
//連接zookeeper
@Before
public void before() throws InterruptedException, IOException {
final CountDownLatch countDownLatch=new CountDownLatch(1);
zooKeeper = new ZooKeeper(IP, 6000, new Watcher() {
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
countDownLatch.await();
}
@After
public void after() throws InterruptedException {
zooKeeper.close();
}
@Test
public void watcherGetData1() throws KeeperException, InterruptedException {
// arg1:節點的路徑
// arg2:使用連接對象中的watcher
zooKeeper.getData("/watcher1", true,null);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherGetData2() throws KeeperException, InterruptedException {
Watcher watcher = new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}};
zooKeeper.getData("/watcher1", watcher,null);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherGetData3() throws KeeperException, InterruptedException {
// arg1:節點的路徑
// arg2:使用連接對象中的watcher
zooKeeper.getData("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
},null);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherGetData4() throws KeeperException, InterruptedException {
zooKeeper.getData("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher1");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
},null);
zooKeeper.getData("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher2");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
},null);
Thread.sleep(50000);
System.out.println("結束");
}
}
- 查看子節點
/**
* @Author: zxx
* @Date: 2020/3/30 19:57
* @Description: zk.getChildren(path, watch)**
*/
public class ZKWatcherGetChildren {
private String IP = "192.168.60.130:2181";
public static ZooKeeper zooKeeper;
//連接zookeeper
@Before
public void before() throws InterruptedException, IOException {
final CountDownLatch countDownLatch=new CountDownLatch(1);
zooKeeper = new ZooKeeper(IP, 6000, new Watcher() {
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
countDownLatch.await();
}
@After
public void after() throws InterruptedException {
zooKeeper.close();
}
@Test
public void watcherGetChildren1() throws KeeperException, InterruptedException {
// arg1:節點的路徑
// arg2:使用連接對象中的watcher
zooKeeper.getChildren("/watcher1", true);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherGetChildren2() throws KeeperException, InterruptedException {
Watcher watcher = new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}};
zooKeeper.getChildren("/watcher1", watcher);
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherGetChildren3() throws KeeperException, InterruptedException {
zooKeeper.getChildren("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
Thread.sleep(50000);
System.out.println("結束");
}
@Test
public void watcherGetChildren4() throws KeeperException, InterruptedException {
zooKeeper.getChildren("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher1");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
zooKeeper.getChildren("/watcher1", new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("自定義watcher2");
System.out.println("path=" + watchedEvent.getPath());
System.out.println("eventType=" + watchedEvent.getType());
}
});
Thread.sleep(50000);
System.out.println("結束");
}
}