zookeeper的watcher机制

Zookeeper的分布式通知功能依赖于watcher机制。当客户端向节点注册watcher,服务端触发后,会通知客户端,客户端回调相应方法。该机制通过最小化通信、一次性watcher和队列串行执行确保轻量级且有序的通知。主要涉及的方法包括客户端构造时设置默认watcher,getData、getChildren和exists的watcher注册,以及服务端的watcher触发和客户端的响应处理。
摘要由CSDN通过智能技术生成

zookeeper的分布式订阅/通知功能就是由watcher实现的。利用watcher的通知可以实现许多功能,比如分布式锁、分布式队列。

他的实现原理很简单:客户端向某一个节点注册watcher,服务端触发watcher通知到客户端,客户端调用对应watcher的回调方法。

下边分析源码:

我们先看一下哪些方法里有watcher:

1、首先,在创建zookeeper客户端的时候传入了一个watcher的实现,这个watcher将被作为该客户端的默认watcher。

构造方法列表:

客户端具体构造:

    public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher,
                     boolean canBeReadOnly)
            throws IOException
    {
        LOG.info("Initiating client connection, connectString=" + connectString
                + " sessionTimeout=" + sessionTimeout + " watcher=" + watcher);
        //客户端默认watcher
        watchManager.defaultWatcher = watcher;

        ConnectStringParser connectStringParser = new ConnectStringParser(
                connectString);
        HostProvider hostProvider = new StaticHostProvider(
                connectStringParser.getServerAddresses());
        cnxn = new ClientCnxn(connectStringParser.getChrootPath(),
                hostProvider, sessionTimeout, this, watchManager,
                getClientCnxnSocket(), canBeReadOnly);
        cnxn.start();
    }


2、getData、getChildren和exist方法都有可以传入一个watcher实现的重载方法。




注意到上图中有一些重载方法可以传入一个布尔值的watch,如果传true,将会使用构造客户端时传入的默认watcher。如下
    public byte[] getData(String path, boolean watch, Stat stat)
            throws KeeperException, InterruptedException {
        //如果为true,则使用默认watcher
        return getData(path, watch ? watchManager.defaultWatcher : null, stat);
    }

了解完了哪里用到watcher,我们看看是怎么实现通知的,以getData为例:

1、客户端注册:
 public byte[] getData(final String path, Watcher watcher, Stat stat)
            throws KeeperException, InterruptedException
    {
        final String clientPath = path;
        //首先验证路径是否正确
        PathUtils.validatePath(clientPath);

        // the watch contains the un-chroot path
        WatchRegistration wcb = null;
        if (watcher != null) {
            //如果watcher不为空,则包装成一个WatchRegistration对象
            wcb = new DataWatchRegistration(watcher, clientPath);
        }
        //增加前缀路径
        final String serverPath = prependChroot(clientPath);

        //设置request,如果需要注册watcher则将setWatch设为true,提交请求
        RequestHeader h = new RequestHeader();
        h.setType(ZooDefs.OpCode.getData);
        GetDataRequest request = new GetDataRequest();
        request.setPath(serverPath);
        request.setWatch(watcher != null);
        GetDataResponse response = new GetDataResponse();
        
        ReplyHeader r = cnxn.submitRequest(h, request, response, web);      
        if (r.getErr() != 0) {
            throw KeeperException.create(KeeperException.Code.get(r.getErr()),
                    clientPath);
        }
        if (stat != null) {
            DataTree.copyStat(response.getStat(), stat);
        }
        return response.getData();
    }
    public ReplyHeader submitRequest(RequestHeader h, Record request,
                                     Record response, WatchRegistration watchRegistration)
            throws InterruptedException {
        ReplyHeader r = new ReplyHeader();
        //将请求包装成packet对象并加入到发送队列等待发送
        Packet packet = queuePacket(h, r, request, response, null, null, null,         
        null, watchRegistration);
        synchronized (packet) {
            while (!packet.finished) {
                //请求结束之前一直等待
                packet.wait();                
            }
        }
        return r;
    }
   Packet queuePacket(RequestHeader h, ReplyHeader r, Record request,
                       Record response, AsyncCallback cb, String clientPath,
                       String serverPath, Object ctx, WatchRegistration watchRegistration)
    {
        Packet packet = null;
        synchronized (outg
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值