Zookeeper 的观察者(Watcher)机制是一种事件通知机制,允许客户端在 ZNode 上设置观察者,以便在 ZNode 的数据或状态发生变化时接收通知。Watcher 机制在分布式系统中非常有用,因为它提供了一种高效的方式来监视配置变化、节点状态等。
Watcher 机制的关键特性
- 一次性:Watcher 是一次性的,当触发一次后就需要重新设置。
- 异步通知:Watcher 通过异步回调通知客户端,不阻塞客户端的操作。
- 轻量级:Watcher 是轻量级的,适用于高频次、高并发的场景。
代码示例
以下代码示例展示了如何使用 Zookeeper 的 Watcher 机制,监视某个 ZNode 的数据变化,并在变化时接收通知。
1. 添加 Maven 依赖
在 pom.xml 中添加 Zookeeper 客户端的依赖:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.3</version>
</dependency>
2. 创建 Zookeeper 客户端
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
public class ZookeeperClient {
private static final String ZK_ADDRESS = "localhost:2181";
private static final int SESSION_TIMEOUT = 3000;
private ZooKeeper zooKeeper;
public void connect() throws Exception {
zooKeeper = new ZooKeeper(ZK_ADDRESS, SESSION_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("Default event received: " + event);
}
});
}
public void close() throws InterruptedException {
if (zooKeeper != null) {
zooKeeper.close();
}
}
public ZooKeeper getZooKeeper() {
return zooKeeper;
}
}
3. 设置 Watcher 并监视 ZNode
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class ZookeeperWatcherExample {
private static final String WATCHER_PATH = "/watcher_node";
public static void main(String[] args) throws Exception {
ZookeeperClient client = new ZookeeperClient();
client.connect();
ZooKeeper zooKeeper = client.getZooKeeper();
// 创建持久节点
if (zooKeeper.exists(WATCHER_PATH, false) == null) {
String createdPath = zooKeeper.create(WATCHER_PATH, "initial_data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("Created node path: " + createdPath);
}
// 设置 Watcher
setWatcher(zooKeeper, WATCHER_PATH);
// 模拟数据变化
simulateDataChange(zooKeeper, WATCHER_PATH);
// 保持程序运行,以便接收 Watcher 事件
Thread.sleep(30000);
client.close();
}
private static void setWatcher(ZooKeeper zooKeeper, String path) throws Exception {
byte[] data = zooKeeper.getData(path, new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("Watcher event received: " + event);
if (event.getType() == Event.EventType.NodeDataChanged) {
try {
// 重新设置 Watcher
setWatcher(zooKeeper, path);
// 获取新的数据
byte[] newData = zooKeeper.getData(path, false, null);
System.out.println("Updated data of node " + path + ": " + new String(newData));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, null);
System.out.println("Initial data of node " + path + ": " + new String(data));
}
private static void simulateDataChange(ZooKeeper zooKeeper, String path) throws Exception {
new Thread(() -> {
try {
Thread.sleep(5000);
zooKeeper.setData(path, "updated_data_1".getBytes(), -1);
Thread.sleep(5000);
zooKeeper.setData(path, "updated_data_2".getBytes(), -1);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
详细解释
-
创建会话:
- 使用
ZooKeeper构造函数创建一个新的会话,指定 Zookeeper 服务器地址和会话超时时间。 Watcher接口的实现处理会话相关的事件,如会话失效。
- 使用
-
设置 Watcher:
- 使用
getData方法获取节点数据时,传入一个实现了Watcher接口的对象。 - 当节点数据发生变化时,
Watcher的process方法会被调用。
- 使用
-
处理 Watcher 事件:
- 在
process方法中处理 Watcher 事件。 - 重新设置 Watcher,因为 Watcher 是一次性的。
- 获取节点的最新数据。
- 在
-
模拟数据变化:
- 使用
setData方法模拟节点数据的变化,触发 Watcher 事件。
- 使用
Watcher 事件类型
Zookeeper 的 Watcher 事件类型主要包括以下几种:
- NodeCreated:节点被创建。
- NodeDeleted:节点被删除。
- NodeDataChanged:节点数据被修改。
- NodeChildrenChanged:子节点列表发生变化。
总结
Zookeeper 的 Watcher 机制是一种高效的事件通知机制,允许客户端监视 ZNode 的数据或状态变化。Watcher 是一次性的,需要在每次事件触发后重新设置。通过上述代码示例,可以看到如何使用 Watcher 机制监视 ZNode 的数据变化,处理 Watcher 事件,并重新设置 Watcher。了解 Watcher 机制有助于在实际应用中实现高效的分布式协调和管理。