Zookeeper(4)事件监听机制

596 阅读5分钟

1.zookeeper的事件监听机制

zookeeper提供了数据的发布订阅功能,监听者通过注册监听器,监听不同的节点,当节点的数据发生变化时,会通知监听者

zookeeper的监听机制采用异步回调的方式,客户端不用一直轮询状态的变化,减少了客户端的压力

(一)watcher的架构

zookeeper的监听器的组成:

  • zookeeper客户端
  • zookeeper服务端
  • zookeeper客户端的ZKWatcherManager对象

(二)监听原理

(1)客户端将watcher注册到服务端

(2)客户端将watcher对象同时注册到客户端的ZKWatcherManager对象中

(3)Zookeeper服务端监听到数据发生变化,服务端会主动通知客户端,客户端的ZKWatcherManager对象主动调用对应的watcher进行处理

Zookeeper的回调过程

(三)Zookeeper监听器的特点

(1)一次性:watcher是一次性的,一旦被触发就会被移除,再次使用时需要重新进行注册

(2)客户端循序回调:watcher的回调是顺序执行的,只有回调后客户端才能看见最新的数据状态,回调函处理逻辑不应该过于复杂,以免影响其他watcher逻辑的执行

(3)轻量级:WatchEvent是最小的通信单元,结构上只包含通知状态、事件类型和节点路径,并不会告诉数据节点变化前后的具体内容;

(4)时效性: watcher只有在当前session彻底失效时才会无效,若在session有效期内快速重连成功,则watcher依然存在,仍可接收到通知;

(四)watcher的通知状态(KeeperState)

keeperstate描述的是客户端与服务器端的链接状态,状态的类型是一个枚举类,位于org.apache.zookeeper.Watcher.Event.KeeperState下,枚举类的属性如下:

枚举属性说明
SyncConnected客户端与服务器正常连接时
Disconnected客户端与服务器断开连接时
Expired会话session失效时
AuthFailed身份认证失败时

(五)watcher的事件类型(EventType)

EventType描述的是数据节点发生变化时对应的通知类型,只有当KeeperState为SyncConnected状态下时EventType才有效,当keeperstate发生变化时,EventType永远为null,EventType的状态类型也是一个枚举类,位于org.apache.zookeeper.Watcher.Event.EventType包下,枚举类的属性如下:

枚举属性说明
None
NodeCreatedWatcher监听的数据节点被创建时
NodeDeletedWatcher监听的数据节点被删除时
NodeDataChangedWatcher监听的数据节点内容发生变更时(无论内容数据是否变化)
NodeChildrenChangedWatcher监听的数据节点的子节点列表发生变更时

(六)注册监听实现的方式

zookeeper中采用zk.getChildren(path, watch)、zk.exists(path, watch)、zk.getData(path, watcher, stat)这样的方式为某个znode注册监听。

下表以node-x节点为例,说明调用的注册方法和可监听事件间的关系:

注册方式CreatedChildrenChangedChangedDeleted
zk.exists(“/node-x”,watcher)可监控可监控可监控
zk.getData(“/node-x”,watcher)可监控可监控
zk.getChildren(“/node-x”,watcher)可监控可监控

注意:客户端接收到的相关事件通知中只包含状态及类型等信息,不包括节点变化前后的 具体内容,变化前的数据需业务自身存储,变化后的数据需调用get等方法重新获取;

2.Zookeeper监听事件的代码实现

(一)查看链接状态

在new Zookeeper对象时,传入watcher对象,可以监控链接状态

event.getType()
public class c08监控查看链接状态 implements Watcher{

    static String ip = "mymv:2181";
    // 计数器对象
    static CountDownLatch countDownLatch = new CountDownLatch(1);
    // 连接对象
    static ZooKeeper zooKeeper;

    @Override
    public void process(WatchedEvent event) {

        //得到通知类型,当链接状态变化时,事件类型为none
        if (event.getType() == Event.EventType.None) {
            if (event.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("链接创建成功");
                countDownLatch.countDown();
            }else if (event.getState() == Event.KeeperState.Disconnected) {
                System.out.println("断开链接");
            }else if (event.getState() == Event.KeeperState.Expired) {
                System.out.println("会话超时");
                try {
                    zooKeeper = new ZooKeeper(ip, 5000, new c08监控查看链接状态());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else if (event.getState() == Event.KeeperState.AuthFailed) {
                System.out.println("认证失败");
            }
        }
    }

    public static void main(String[] args) {
        try {
            zooKeeper = new ZooKeeper(ip, 5000, new c08监控查看链接状态());
            // 阻塞线程等待连接的创建
            countDownLatch.await();
            // 会话id
            System.out.println(zooKeeper.getSessionId());
            // 添加授权用户
            zooKeeper.addAuthInfo("digest","author:123456".getBytes());
            //添加监控节点,是否使用连接对象中注册的监视器。,Stat对象
            byte [] bs=zooKeeper.getData("/create/nodeCode",false,null);
            System.out.println(new String(bs));
            Thread.sleep(50000);
            zooKeeper.close();
            System.out.println("结束");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

(二)exists()监控节点是否存在

// 使用连接对象的监视器
exists(String path, boolean b)
// 自定义监视器
exists(String path, Watcher w)
public class c09监控查看节点是否存在 {
    String ip = "mymv:2181";
    ZooKeeper zooKeeper = null;

    @Before
    public void before() throws IOException, InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        // 连接zookeeper客户端
        zooKeeper = new ZooKeeper(ip, 6000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("连接对象的参数!");
                // 连接成功
                if (event.getState() == Event.KeeperState.SyncConnected)
                {
                    countDownLatch.countDown();
                }
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        });
        countDownLatch.await();
    }

    @After
    public void after() throws InterruptedException {
        zooKeeper.close();
    }

    @Test
    public void watcherExists2() throws KeeperException, InterruptedException {
        zooKeeper.exists("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        });
        Thread.sleep(50000);
        System.out.println("结束");
    }


    @Test
    public void watcherExists3() throws KeeperException, InterruptedException {
        zooKeeper.exists("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        });

        zooKeeper.exists("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        });
        Thread.sleep(50000);
        System.out.println("结束");
    }
}

(三)gerData()查看节点注册监控器

// 使用连接对象的监视器
getData(String path, boolean b, Stat stat)
// 自定义监视器
getData(String path, Watcher w, Stat stat)

public class c10监控查看节点 {

    String ip = "mymv:2181";
    ZooKeeper zooKeeper = null;

    @Before
    public void before() throws IOException, InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        // 连接zookeeper客户端
        zooKeeper = new ZooKeeper(ip, 6000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("连接对象的参数!");
                // 连接成功
                if (event.getState() == Event.KeeperState.SyncConnected)
                {
                    countDownLatch.countDown();
                }
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        });
        countDownLatch.await();
    }

    @After
    public void after() throws InterruptedException {
        zooKeeper.close();
    }

    @Test
    public void watcherGet1() throws KeeperException, InterruptedException {
        zooKeeper.getData("/create/node3",false,new Stat());
        Thread.sleep(50000);
        System.out.println("结束");
    }


    @Test
    public void watcherGet2() throws KeeperException, InterruptedException {
        zooKeeper.getData("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        },null);
        Thread.sleep(50000);
        System.out.println("结束");
    }

    @Test
    public void watcherGet3() throws KeeperException, InterruptedException {
        zooKeeper.getData("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        },null);

        zooKeeper.getData("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        },null);
        Thread.sleep(50000);
        System.out.println("结束");
    }
}

(四)getChildren()查看子节点注册监控器

// 使用连接对象的监视器
getChildren(String path, boolean b)
// 自定义监视器
getChildren(String path, Watcher w)

public class c11监控查看子节点 {

    String ip = "mymv:2181";
    ZooKeeper zooKeeper = null;

    @Before
    public void before() throws IOException, InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        // 连接zookeeper客户端
        zooKeeper = new ZooKeeper(ip, 6000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("连接对象的参数!");
                // 连接成功
                if (event.getState() == Event.KeeperState.SyncConnected)
                {
                    countDownLatch.countDown();
                }
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        });
        countDownLatch.await();
    }

    @After
    public void after() throws InterruptedException {
        zooKeeper.close();
    }

    @Test
    public void watcherChildren1() throws KeeperException, InterruptedException {
        zooKeeper.getChildren("/create/node3",true);
        Thread.sleep(50000);
        System.out.println("结束");
    }


    @Test
    public void watcherChildren12() throws KeeperException, InterruptedException {
        zooKeeper.getChildren("/create/node3", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("自定义watcher");
                System.out.println("path=" + event.getPath());
                System.out.println("eventType=" + event.getType());
            }
        },null);
        Thread.sleep(50000);
        System.out.println("结束");
    }
}