zookeeper-事件監聽機制(3)

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("結束");
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章