1、背景

Zookeeper要想实时的获取ZNode的数据状态,如果轮询获取的话,实时性差,资源利用率低,浪费CPU资源,如果是Zookeeper服务端主动推送,会节省大量的资源。Zookeeper服务端通过Watcher机制来实现事件通知。

2、原理

Watcher注册和通知流程图.png

  1. Zookeeper客户端向Zookeeper服务端注册想要监听的节点状态。
  2. 客户端在WatchManager中本地存储监听器相关信息。
  3. Zookeeper服务端监听的数据状态发生变化。
  4. Zookeeper主动发送相应的事件信息给相关会话客户端。
  5. 客户端在本地响应式的回掉Watcher的process方法。

3、简单源码分析

客户端使用Zookeeper主要关注两个类:org.apache.zookeeper.Watcher与org.apache.zookeeper.WatchedEvent。

3.1、org.apache.zookeeper.Watcher

一般想要注册监听,先要实现Watcher接口里的process方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 节点watcher
*/
private Watcher baseNodeWatcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
String path = event.getPath();
Event.EventType type = event.getType();
if (type == Event.EventType.NodeChildrenChanged) {
// 子节点新增或者减少
}
}
};

Watcher接口中除了process方法外,还有Event接口,内部含有连个枚举类:KeeperState、EventType事件的状态和类型。
通知状态与事件.jpg

3.2、org.apache.zookeeper.WatchedEvent

WatchedEvent非常轻量级:

1
2
3
final private KeeperState keeperState;
final private EventType eventType;
private String path;

是不包含节点变化的内容的,所以根据业务需求,会需要主动拉取数据,即推拉结合方式。

4、特点

  • 单次触发
    状态变更一次,就触发一次事件推送,所以在开发过程中,每次收到事件推送后,要重新注册监听。
    既然是一次发送,那必然会有事件通知的丢失,根据业务场景采用推拉结合的方案,也不会有太大的问题。
  • 优先通知
    事件触发时,是先通知Client,再更新节点,顺序性。
  • 会话关联
    当会话过期时,监听会失效。
  • 跨集群
    Client与Zookeeper服务器节点断开时,连接到其他服务器,Client会重新将未触发的监视点列表在新的服务器上注册。
  • 无法移除
    只有两种方法能移除监视点:1、触发事件;2、会话过期或者关闭。
  • 轻量级设计
    WatchEvent是Zookeeper整个Watcher通知机制的最小通知单元,只包含三部分数据:通知状态、事件类型、节点路径。

参考

Zookeeper Watch机制
ZooKeeper 技术内幕:watcher 监视点
ZooKeeper Watcher机制
品味ZooKeeper之Watcher机制
Apache ZooKeeper Watcher 机制源码解释
《ZooKeeper-分布式过程协同技术详解》

tencent.jpg