• 吴裕雄--天生自然 Zookeeper学习笔记--Zookeeper watcher 事件机制原理剖析


    zookeeper 的 watcher 机制,可以分为四个过程:
    
    客户端注册 watcher。
    服务端处理 watcher。
    服务端触发 watcher 事件。
    客户端回调 watcher。
    其中客户端注册 watcher 有三种方式,调用客户端 API 可以分别通过 getData、exists、getChildren 实现,利用前面章节创建的 maven 工程,新建 WatcherDemo 类,以 exists 方法举例说明其原理。
    实例
    public class WatcherDemo implements Watcher {
        static ZooKeeper zooKeeper;
        static {
            try {
                zooKeeper = new ZooKeeper("192.168.3.39:2181", 4000,new WatcherDemo());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void process(WatchedEvent event) {
            System.out.println("eventType:"+event.getType());
            if(event.getType()==Event.EventType.NodeDataChanged){
                try {
                    zooKeeper.exists(event.getPath(),true);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
            String path="/watcher";
            if(zooKeeper.exists(path,false)==null) {
                zooKeeper.create("/watcher", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            Thread.sleep(1000);
            System.out.println("-----------");
            //true表示使用zookeeper实例中配置的watcher
            Stat stat=zooKeeper.exists(path,true);
            System.in.read();
        }
    }

     

     

    1、客户端发送事件通知请求
    在 Zookeeper 类调用 exists 方法时候,把创建事件监听封装到 request 对象中,watch 属性设置为 true,待服务端返回 response 后把监听事件封装到客户端的 ZKWatchManager 类中。

    2、服务端处理 watcher 事件的请求
    服务端 NIOServerCnxn 类用来处理客户端发送过来的请求,最终调用到 FinalRequestProcessor,其中有一段源码添加客户端发送过来的 watcher 事件:

    然后进入 statNode 方法,在 DataTree 类方法中添加 watcher 事件,并保存至 WatchManager 的 watchTable 与 watchTable 中。

     

    3、服务端触发 watcher 事件流程:
    若服务端某个被监听的节点发生事务请求,服务端处理请求过程中调用 FinalRequestProcessor 类 processRequest 方法中的代码如下所示:

     

     

     

     

    package com.runoob.zookeeper;
    
    import org.apache.zookeeper.*;
    
    import java.io.IOException;
    import java.util.concurrent.CountDownLatch;
    
    
    public class ConnectionDemo {
    
        public static void main(String[] args) {
            try {
                final CountDownLatch countDownLatch=new CountDownLatch(1);
                ZooKeeper zooKeeper=
                        new ZooKeeper("192.168.3.35:2181" ,
                                4000, new Watcher() {
                            @Override
                            public void process(WatchedEvent event) {
                                if(Event.KeeperState.SyncConnected==event.getState()){
                                    //如果收到了服务端的响应事件,连接成功
                                    countDownLatch.countDown();
                                }
                            }
                        });
                countDownLatch.await();
                System.out.println(zooKeeper.getState());
                zooKeeper.create("/runoob","0".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (KeeperException e) {
                e.printStackTrace();
            }
        }
    }
    package com.runoob.zookeeper;
    
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.retry.ExponentialBackoffRetry;
    import org.apache.zookeeper.data.Stat;
    
    
    public class CuratorDemo {
    
        public static void main(String[] args) throws Exception {
            CuratorFramework curatorFramework=CuratorFrameworkFactory.
                    builder().connectString("192.168.3.33:2181," +
                    "192.168.3.35:2181,192.168.3.37:2181").
                    sessionTimeoutMs(4000).retryPolicy(new
                    ExponentialBackoffRetry(1000,3)).
                    namespace("").build();
            curatorFramework.start();
            Stat stat=new Stat();
            byte[] bytes = curatorFramework.getData().storingStatIn(stat).forPath("/runoob");
            System.out.println(new String(bytes));
            curatorFramework.close();
        }
    }
    package com.runoob.zookeeper;
    
    import org.apache.zookeeper.*;
    import org.apache.zookeeper.data.Stat;
    
    import java.io.IOException;
    
    public class WatcherDemo implements Watcher {
        static ZooKeeper zooKeeper;
        static {
            try {
                zooKeeper = new ZooKeeper("192.168.3.39:2181", 4000,new WatcherDemo());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void process(WatchedEvent event) {
            System.out.println("eventType:"+event.getType());
            if(event.getType()==Event.EventType.NodeDataChanged){
                try {
                    zooKeeper.exists(event.getPath(),true);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
            String path="/watcher";
            if(zooKeeper.exists(path,false)==null) {
                zooKeeper.create("/watcher", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            Thread.sleep(1000);
            System.out.println("-----------");
            //true表示使用zookeeper实例中配置的watcher
            Stat stat=zooKeeper.exists(path,true);
            System.in.read();
        }
    }
    package com.runoob.zookeeper;
    
    import static org.junit.Assert.assertTrue;
    
    import org.junit.Test;
    
    /**
     * Unit test for simple ConnnectedDemo.
     */
    public class ConnnectedDemoTest
    {
        /**
         * Rigorous Test :-)
         */
        @Test
        public void shouldAnswerWithTrue()
        {
            assertTrue( true );
        }
    }
  • 相关阅读:
    卡牌分组
    css字体样式+文本样式
    jQuery---on注册事件的2种方式
    css3神奇的背景控制属性+使用颜色过渡实现漂亮的渐变效果
    js Dom为页面中的元素绑定键盘或鼠标事件
    ES6中Set和WeakSet
    Vue之计算属性Computed和属性监听Watch,Computed和Watch的区别
    JS数据类型和堆栈+变量比较和值的复制+参数传递和类型检测
    复习node中加载静态资源--用express+esj
    种花问题
  • 原文地址:https://www.cnblogs.com/tszr/p/14390114.html
Copyright © 2020-2023  润新知