Watcher是Zookeeper中实现的事件通知机制,当发生变动的时候会通知Client,Zookeeper中Client操作注册的Watcher都为一次性Watcher,除去特殊事件类型,事件类型如下:
None (-1),
NodeCreated (1),
NodeDeleted (2),
NodeDataChanged (3),
NodeChildrenChanged (4);
当类型为None时,主要是
Session expired / connection loss/ auth failed的时候触发的事件,该类型事件的Watcher会在Zookeeper Client重新连接后再次注册,不会丢弃。
所有注册的Watcher在Client中会加入到waitEvent队列中,只有得到事件通知并且非None类型的事件的时候才会丢弃,并且被GC回收,因为Watcher是一次性通知,所以在通常情况的使用是
每次都New一个新的Watcher注册在服务端,此时如果Watcher过多则会导致OutOfMemoryError: Java heap space。错误代码如下:
public class TestLock {
public static void main(String[] args) throws InterruptedException, IOException {
Configuration conf = SearcherConfiguration.create();
ZookeeperClient zk = SearcherUtils.getZKClient(conf
.get("searcher.thinkingguide.zk.address"), conf.getInt(
"searcher.thinkingguide.zk.timeout", 3000), conf
.get("searcher.thinkingguide.zk.lock.dir"), conf
.get("searcher.thinkingguide.zk.root.dir"), conf
.get("searcher.thinkingguide.zk.id.node"));
while(true){
try {
zk.exists("/dd", new TestWatcher());
} catch (KeeperException e) {
e.printStackTrace();
}
Thread.sleep(30);
}
}
static class TestWatcher implements Watcher{
private long[] test;
public TestWatcher(){
this.test = new long[1000000]; //创建一个占用Client大内存的数组,以便测试内存溢出
}
@Override
public void process(WatchedEvent event) {
System.out.println("===============");
}
}
}
以上示例在运行几分钟之后就会出现OutOfMemoryError: Java heap space。所以在使用Zookeeper Watcher的时候一定要注意这点。
建议做法是在循环中使用wait,并且在Watcher触发的时候notify()。