ZooKeeper之Watcher机制
1.watcher原理框架

zk的watcher由客户端,客户端WatchManager,zk服务器组成。整个过程涉及了消息通信及数据存储。
- zk客户端向zk服务器注册watcher的同时,会将watcher对象存储在客户端的watchManager。
- Zk服务器触发watcher事件后,会向客户端发送通知,客户端线程从watchManager中回调watcher执行相应的功能。
EventType完整的类名是org.apache.zookeeper.Watcher.Event.EventType

- NodeDataChanged事件
无论节点数据发生变化还是数据版本发生变化都会触发
即使被更新数据与新数据一样,数据版本dataVersion都会发生变化
- NodeChildrenChanged
新增节点或者删除节点
- AuthFailed
重点是客户端会话没有权限而是授权失败
watcher注册过程
创建zk客户端对象实例时注册:
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd) ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)
通过这种方式注册的watcher将会作为整个zk会话期间的默认watcher,会一直被保存在客户端ZK WatchManager 的 defaultWatcher 中,如果这个被创建的节点在其它时候被创建watcher并注册,则这个默认的watcher会被覆盖。注意注意注意,watcher触发一次就会失效,不管是创建节点时的 watcher 还是以后创建的 watcher。
其他注册watcher的API:
getChildren(String path, Watcher watcher)getChildren(String path, boolean watch)- Boolean watch表示是否使用上下文中默认的watcher,即创建zk实例时设置的watcher
getData(String path, boolean watch, Stat stat)- Boolean watch表示是否使用上下文默认的watcher,即创建zk实例时设置的watcher
getData(String path, Watcher watcher, AsyncCallback.DataCallback cb, Object ctx)exists(String path, boolean watch)- Boolean watch表示是否使用上下文中默认的watcher,即创建zk实例时设置的watcher
exists(String path, Watcher watcher)
wather的特性:一次性,客户端串行执行,轻量。
一次性:对于ZK的watcher,只需要记住一点:zookeeper有watch事件,是一次性触发的,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher,由于zookeeper的监控都是一次性的,所以每次都必须监控。
客户端串行执行:客户端watcher回调的过程是一个串行同步的过程,这为我们保证了顺序,同时需要开发人员注意一点,千万不用因为一个watcher的处理逻辑影响了整个客户端的watcher回调。
轻量:WatcherEvent是Zookeeper整个Watcher通知机制的最小通知单元。整个单元结构只包含三部分:通知状态,事件类型和节点路径。也就是说Watcher通知非常的简单,只会告诉客户端发生了事件而不会告知其具体内容,需要客户自己去进行获取,而不会直接提供具体的数据内容。
package com.smart.zookeeper; import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; public class ZooKeeperWatcher implements Watcher { private AtomicInteger seq = new AtomicInteger(); private static final int SESSION_TIMEOUT = 10000; private static final String CONNECT_ADDRESS = "192.168.223.142:2181"; /** * 父路径 */ private static final String ROOT_PATH = "/root"; /** * 子路径 */ private static final String CHILD_PATH = "/root/child"; private ZooKeeper zk = null; /** * 用于等待zookeeper连接建立之后 通知阻塞程序继续向下执行 */ private CountDownLatch countDownLatch = new CountDownLatch(1); /** * 创建连接 * * @param connectAddr ZK服务器地址列表 * @param sessionTimeout Session超时时间 */ public void createConnection(String connectAddr, int sessionTimeout) { releaseConnection(); try { //this表示把当前对象进行传递到其中去(也就是在主函数里实例化的new ZooKeeperWatcher()实例对象) zk = new ZooKeeper(connectAddr, sessionTimeout, this); System.out.println("开始连接ZK服务器"); countDownLatch.await(); } catch (Exception e) { e.printStackTrace(); } } /** * 关闭ZK连接 */ public void releaseConnection() { try { if (zk != null) { zk.close(); } } catch (InterruptedException e) { e.printStackTrace(); } } /** * 创建节点 * * @param path * @param data * @param isWatch * @return */ public boolean createPath(String path, String data, boolean isWatch) { try { Stat stat = zk.exists(path, isWatch); if (stat == null) { String nodePath = zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("创建节点成功 path:" + nodePath); } } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 读取指定节点的内容 * * @param path * @param isWatch * @return */ public String readData(String path, boolean isWatch) { try { return new String(zk.getData(path, isWatch, null)); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return null; } /** * 更新指定的节点的数据 * * @param path * @param data * @return */ public boolean writeData(String path, String data) { try { zk.setData(path, data.getBytes(), -1); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 删除指定的节点 * * @param path */ public void deleteNode(String path) { try { zk.delete(path, -1); } catch (InterruptedException e) { e.printStackTrace(); } catch (KeeperException e) { e.printStackTrace(); } } /** * 删除所有节点 */ public void deleteAllNode(boolean isWatcher) throws KeeperException, InterruptedException { if (zk.exists(CHILD_PATH, isWatcher) != null) { deleteNode(CHILD_PATH); } if (zk.exists(ROOT_PATH, isWatcher) != null) { deleteNode(ROOT_PATH); } } @Override public void process(WatchedEvent watchedEvent) { System.out.println("event :" + watchedEvent); if (watchedEvent == null) return; //连接状态 Event.KeeperState state = watchedEvent.getState(); //事件类型 Event.EventType eventType = watchedEvent.getType(); //受影响path String path = watchedEvent.getPath(); System.out.println("连接状态:\t" + state.toString()); System.out.println("事件类型:\t" + eventType.toString()); if (Event.KeeperState.SyncConnected == state) { // 成功连接上ZK服务器 if (Event.EventType.None == eventType) { System.out.println("成功连接上ZK服务器"); countDownLatch.countDown(); } else if (Event.EventType.NodeCreated == eventType) { System.out.println("节点创建"); } else if (Event.EventType.NodeDataChanged == eventType) { System.out.println("节点数据更新"); } else if (Event.EventType.NodeChildrenChanged == eventType) { System.out.println("子节点变更"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } else if (Event.EventType.NodeDeleted == eventType) { System.out.println("节点 " + path + " 被删除"); } } else if (Event.KeeperState.Disconnected == state) { System.out.println("与ZK服务器断开连接"); } else if (Event.KeeperState.AuthFailed == state) { System.out.println("权限检查失败"); } else if (Event.KeeperState.Expired == state) { System.out.println("会话失效"); } } public static void main(String[] args) throws InterruptedException, KeeperException { ZooKeeperWatcher zkWatcher = new ZooKeeperWatcher(); zkWatcher.createConnection(CONNECT_ADDRESS, SESSION_TIMEOUT); System.out.println("--------"+zkWatcher.zk.toString()); if(zkWatcher.createPath(ROOT_PATH, System.currentTimeMillis() + "", false)) { Thread.sleep(1000); // 读取数据 zkWatcher.readData(ROOT_PATH, false); // 更新数据 zkWatcher.writeData(ROOT_PATH, System.currentTimeMillis() + ""); Thread.sleep(1000); // 创建子节点 zkWatcher.createPath(CHILD_PATH, System.currentTimeMillis() + "", false); //在进行修改之前,我们需要watch一下这个节点: Thread.sleep(1000); zkWatcher.readData(CHILD_PATH, true); zkWatcher.writeData(CHILD_PATH, System.currentTimeMillis() + ""); } zkWatcher.deleteAllNode(false); zkWatcher.releaseConnection(); } }
浙公网安备 33010602011771号