Zookeeper教程(三):ZooKeeper源码阅读之Worker机制及集群状态监控

本文深入解析Zookeeper的Worker机制,包括客户端注册Watcher、服务端处理Watcher的流程,并探讨了如何利用Worker进行集群状态监控。文章通过源码分析,详细介绍了Watcher在ZooKeeper中的工作原理,包括WatcherManager、WatchedEvent、Watcher接口等关键组件。此外,还提供了集群监控的示例。
摘要由CSDN通过智能技术生成

前言:接下来将会着重解释一下ZooKeeper里面重要的代码,本次将针对Worker机制,以及运用Worker进行对集群状态进行监控。如果对Zookerper的安装配置和运用不了解的,可以看看上两篇文章:(1)Zookeeper教程(一):快速开始以及结合java实现分布式Barrier和Queue (2) Zookeeper教程(二):ZooKeeper与Dubbo结合以及原理讲解

(一)Worker原理和源代码解析
(1)原理:
客户端向服务端注册一个Watcher监听,服务端特定事件发生后,触发这个Watcher,接着向指定客户端发送一个事件通知。原理挺简单,那么是如何实现的呢?
(2)结合源码进行解析
Watcher机制主要包括了客户端,客户端WatchManager,ZooKeeper服务端三部分。客户端在服务端注册Watcher的时候,同时将Watcher对象存储在WatchManager中,当服务端触发了Watcher事件后,会向客户端发送通知,客户端此时通过取出相应的Watcher对象来执行。接下来先看一下WatchManager类中部分代码:

(3)WatchManager类

public class WatchManager {
   
    private static final Logger LOG = LoggerFactory.getLogger(WatchManager.class);

    private final HashMap<String, HashSet<Watcher>> watchTable =
        new HashMap<String, HashSet<Watcher>>();

    private final HashMap<Watcher, HashSet<String>> watch2Paths =
        new HashMap<Watcher, HashSet<String>>();

    public synchronized int size(){
        int result = 0;
        for(Set<Watcher> watches : watchTable.values()) {
            result += watches.size();
        }
        return result;
    }
    //同步方法,保证线程安全
    public synchronized void addWatch(String path, Watcher watcher) {
        //先取出所有的watch
        HashSet<Watcher> list = watchTable.get(path);
        if (list == null) {
            // don't waste memory if there are few watches on a node
            // rehash when the 4th entry is added, doubling size thereafter
            // seems like a good compromise
            list = new HashSet<Watcher>(4);
            watchTable.put(path, list);
        }
        list.add(watcher);

        HashSet<String> paths = watch2Paths.get(watcher);
        if (paths == null) {
            // cnxns typically have many watches, so use default cap here
            paths = new HashSet<String>();
            watch2Paths.put(watcher, paths);
        }
        paths.add(path);
    }
}

Watcher注册和通知图例

(4)Watcher接口(代码过长,选取重要部分)

public interface Watcher {
    public interface Event {
            .........
        }
    }
    abstract public void process(WatchedEvent event);
}

在Event里面包含了KeeperState和EventType两个枚举类,详细对应如下:
这里写图片描述

而process方法是一个回调方法(对回调不清楚的可以搜下资料或者在下面评论,我再解释一下),当ZooKeeper向客户端发送一个Watcher事件通知时,客户端就会调用对应的process进行回调。而precess的参数是一个WatchedEvent类型的参数,接下来看看这个类

(5)WatchedEvent类

public class WatchedEvent {
   
    final private KeeperState keeperState;
    final private EventType eventType;
    private String path;
    //省略构造函数和get方法
    /**
     *  Convert WatchedEvent to type that can be sent over network
     */
    public WatcherEvent getWrapper() {
        return new WatcherEvent(eventType.getIntValue(), 
                                keeperState.getIntValue(), 
                                path);
    }
}

从上面可以看出WatchedEvent包含三个属性:通知状态(KeeperState),事件类型(EventType)和节点路径(Path),ZooKeeper调用WatchedEvent对象来封装服务端事件并传递给Watcher,从而方便回调方法process对服务端事件进行处理。
我们注意到在getWrapper中返回了一个WatcherEvent对象,这个对象和WatchedEvent表示同一个事务,都是对服务端时间的封装。不同的是WatchedEvent是一个逻辑事件,用于服务端和客户端程序执行过程中所需的逻辑对象。而通过WatcherEvent的源码我们可以看到它实现了序列化接口,因此可以用于网络传输
于是整个流程就是:服务端调用getWrapper方法包装一

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值