zoukankan      html  css  js  c++  java
  • zookeeper如何永久监听

    转自:http://www.cnblogs.com/viviman/archive/2013/03/11/2954118.html

    一 回调基础知识  

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的集中管理,集群管理,分布式锁等等。

    //创建一个Zookeeper实例,第一个参数为目标服务器地址和端口,第二个参数为Session超时时间,第三个为节点变化时的回调方法
    ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 500000,new Watcher() {
              // 监控所有被触发的事件
               public void process(WatchedEvent event) {
         //dosomething
              }

         });
    将APP1的所有配置配置到/APP1 znode下,APP1所有机器一启动就对/APP1这个节点进行监控(zk.exist("/APP1",true)),并且实现回调方法Watcher,那么在zookeeper上/APP1 znode节点下数据发生变化的时候,每个机器都会收到通知,Watcher方法将会被执行,那么应用再取下数据即可(zk.getData("/APP1",false,null));

    下面表格列出了写操作与ZK内部产生的事件的对应关系:

     

    event For “/path”

    event For “/path/child”

    create(“/path”)

    EventType.NodeCreated

    NA

    delete(“/path”)

    EventType.NodeDeleted

    NA

    setData(“/path”)

    EventType.NodeDataChanged

    NA

    create(“/path/child”)

    EventType.NodeChildrenChanged

    EventType.NodeCreated

    delete(“/path/child”)

    EventType.NodeChildrenChanged

    EventType.NodeDeleted

    setData(“/path/child”)

    NA

    EventType.NodeDataChanged

    而ZK内部的写事件与所触发的watcher的对应关系如下:

    event For “/path”

    defaultWatcher

    exists
    (“/path”)

    getData
    (“/path”)

    getChildren
    (“/path”)

    EventType.None

    EventType.NodeCreated

     

     

    EventType.NodeDeleted

     

    √(不正常)

     

    EventType.NodeDataChanged

     

     

    EventType.NodeChildrenChanged

         

    综合上面两个表,我们可以总结出各种写操作可以触发哪些watcher,如下表所示:

     

    “/path”

    “/path/child”

     

    exists

    getData

    getChildren

    exists

    getData

    getChildren

    create(“/path”)

           

    delete(“/path”)

         

    setData(“/path”)

           

    create(“/path/child”)

       

     

    delete(“/path/child”)

       

    setData(“/path/child”)

         

     

    如果发生session close、authFail和invalid,那么所有类型的wather都会被触发

    zkClient除了做了一些便捷包装之外,对watcher使用做了一点增强。比如subscribeChildChanges实际上是通过exists和getChildren关注了两个事件。这样当create(“/path”)时,对应path上通过getChildren注册的listener也会被调用。另外subscribeDataChanges实际上只是通过exists注册了事件。因为从上表可以看到,对于一个更新,通过exists和getData注册的watcher要么都会触发,要么都不会触发。

    getData,getChildren(),exists()这三个方法可以针对参数中的path设置watcher,当path对应的Node 有相应变化时,server端会给对应的设置了watcher的client 发送一个一次性的触发通知事件。客户端在收到这个触发通知事件后,可以根据自己的业务逻辑进行相应地处理。

    注意这个watcher的功能是一次性的,如果还想继续得到watcher通知,在处理完事件后,要重新register。

     二 测试watcher回调机制

    // Watcher实例

    Watcher wh = new Watcher() {

    public void process(WatchedEvent event) {

    System.out.println("回调watcher实例: 路径" + event.getPath() + " 类型:"

    + event.getType());

    }

    };

     

    ZooKeeper zk = new ZooKeeper("10.15.82.166:3351", 500000, wh);

    System.out.println("---------------------");

    // 创建一个节点root,数据是mydata,不进行ACL权限控制,节点为永久性的(即客户端shutdown了也不会消失)

    zk.exists("/root", true);

    zk.create("/root", "mydata".getBytes(), Ids.OPEN_ACL_UNSAFE,

    CreateMode.PERSISTENT);

    System.out.println("---------------------");

    // 在root下面创建一个childone znode,数据为childone,不进行ACL权限控制,节点为永久性的

    zk.exists("/root/childone", true);

    zk.create("/root/childone", "childone".getBytes(), Ids.OPEN_ACL_UNSAFE,

    CreateMode.PERSISTENT);

    System.out.println("---------------------");

    // 删除/root/childone这个节点,第二个参数为版本,-1的话直接删除,无视版本

    zk.exists("/root/childone", true);

    zk.delete("/root/childone", -1);

    System.out.println("---------------------");

    zk.exists("/root", true);

    zk.delete("/root", -1);

    System.out.println("---------------------");

    // 关闭session

    zk.close();

    ---------------------

    回调watcher实例: 路径null 类型:None

    回调watcher实例: 路径/root 类型:NodeCreated

    ---------------------

    回调watcher实例: 路径/root/childone 类型:NodeCreated

    ---------------------

    回调watcher实例: 路径/root/childone 类型:NodeDeleted

    ---------------------

    回调watcher实例: 路径/root 类型:NodeDeleted

    ---------------------

    三 永久回调 

    3类事件触发wather后就不再作用,也就是所谓的(一次作用),但是,如何永久监听呢?这需要我们再程序逻辑上进行控制,网上有更好的办法,但是,在简单的应用中,可以再wather方法里面再设置监听,这个方法很笨,但是,很有效,达到了预期的效果。

    复制代码
    Watcher wh = new Watcher() {
            public void process(WatchedEvent event) {
                Log.AC_DEBUG("触发回调watcher实例: 路径" + event.getPath() + " 类型:"
                        + event.getType());
    
                if (event.getType() == EventType.None) {
                    try { //
                            // 判断userauth权限是否能访问userpath
                        String auth_type = "digest";
                        zk.addAuthInfo(auth_type, userauth.getBytes());
                        zk.getData(userpath, null, null);
                    } catch (Exception e) {
    //                    e.printStackTrace();
                        Log.AC_ERROR("get node faild:userpath=" + userpath
                                + ",auth=" + userauth + " e:" + e.getMessage());
                        return;
                    }
                    Log.AC_INFO("userpath=" + userpath + " userauth=" + userauth);
                }
    
                try {
    
                    switchinfo = getallswitch(); // 更新userpath和匿名用户路径下的配置信息,监听这些节点
    
                    // 监听用户路径节点
                    Log.AC_DEBUG("lesson user=" + userpath + " node...");
                    zk.exists(userpath, true); // 监听匿名用户路径节点
                    Log.AC_DEBUG("lesson user=" + AnonymousUSERpath + " node...");
                    zk.exists(AnonymousUSERpath, true);
    
                    // 监听用户路径下的开关节点
                    if (zk.exists(userpath, false) != null) {
                        Log.AC_DEBUG("lesson user=" + userpath
                                + " 's swich node...");
                        List<String> swnodes = zk.getChildren(userpath, true); //
                        // 监听switch层节点的变化
                        Iterator<String> it_sw = swnodes.iterator();
                        while (it_sw.hasNext()) {
                            String swpath = userpath + "/" + it_sw.next();
                            Log.AC_DEBUG("lesson user=" + swpath + " node...");
                            zk.exists(swpath, true);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.AC_ERROR("lesson znode error:" + e.getMessage());
                }
            }
        };
  • 相关阅读:
    2015 多校联赛 ——HDU5389(dp)
    spring MVC配置详解
    面试题整理11
    面试题整理09
    Spring和SpringMVC的区别
    SpringMVC01
    js中typeof与instanceof用法小记
    Java 可变参数
    log4j文件的配置
    Hibernate 分组查询 子查询 原生SQL
  • 原文地址:https://www.cnblogs.com/limingluzhu/p/5157038.html
Copyright © 2011-2022 走看看