Zookeeper(7)Zookeeper的观察者(Watcher)机制是什么?

123 阅读3分钟

Zookeeper 的观察者(Watcher)机制是一种事件通知机制,允许客户端在 ZNode 上设置观察者,以便在 ZNode 的数据或状态发生变化时接收通知。Watcher 机制在分布式系统中非常有用,因为它提供了一种高效的方式来监视配置变化、节点状态等。

Watcher 机制的关键特性

  1. 一次性:Watcher 是一次性的,当触发一次后就需要重新设置。
  2. 异步通知:Watcher 通过异步回调通知客户端,不阻塞客户端的操作。
  3. 轻量级: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();
    }
}

详细解释

  1. 创建会话

    • 使用 ZooKeeper 构造函数创建一个新的会话,指定 Zookeeper 服务器地址和会话超时时间。
    • Watcher 接口的实现处理会话相关的事件,如会话失效。
  2. 设置 Watcher

    • 使用 getData 方法获取节点数据时,传入一个实现了 Watcher 接口的对象。
    • 当节点数据发生变化时,Watcherprocess 方法会被调用。
  3. 处理 Watcher 事件

    • process 方法中处理 Watcher 事件。
    • 重新设置 Watcher,因为 Watcher 是一次性的。
    • 获取节点的最新数据。
  4. 模拟数据变化

    • 使用 setData 方法模拟节点数据的变化,触发 Watcher 事件。

Watcher 事件类型

Zookeeper 的 Watcher 事件类型主要包括以下几种:

  1. NodeCreated:节点被创建。
  2. NodeDeleted:节点被删除。
  3. NodeDataChanged:节点数据被修改。
  4. NodeChildrenChanged:子节点列表发生变化。

总结

Zookeeper 的 Watcher 机制是一种高效的事件通知机制,允许客户端监视 ZNode 的数据或状态变化。Watcher 是一次性的,需要在每次事件触发后重新设置。通过上述代码示例,可以看到如何使用 Watcher 机制监视 ZNode 的数据变化,处理 Watcher 事件,并重新设置 Watcher。了解 Watcher 机制有助于在实际应用中实现高效的分布式协调和管理。