原理系列之——zookeeper的watch监控机制

Zookeeper的Watch机制是其实现分布式协调服务的关键,类似于观察者模式。客户端通过注册watch事件,服务端在数据变更时触发回调。本文深入源码,解析客户端的watch注册、回调处理,以及服务端的watch注册与触发过程,揭示了Zookeeper如何高效地处理分布式环境下的数据一致性问题。

在进入今天的正题之前,先来简单介绍下Zookeeper:
  Zookeeper是一个分布式应用程序协调服务,保证数据的一致性,其提供的功能包括:配置维护、域名维护、分布式同步、组服务等。
  watch监控机制是zookeeper的关键技术之一,本文将通过zk的部分源码来简单了解下watch机制的实现原理。

watch监控机制的实现原理

  当今时代,发布订阅场景到处可见,像微信中的公众号消息订阅,或者网购场景下库存消息的订阅通知等等,这些都是属于发布订阅的场景。
  watch监控机制是zk的一个关键技术,zk通过它来实现发布订阅的功能,通过watch我们可以联想到设计模式中的观察者模式,二者确实有点类似,你可以将其看成是分布式场景下的观察者模式。
在这里插入图片描述

客户端watch的注册和回调

客户端watch注册实现过程:
  发送一个带有watch事件的请求——>DataWatchRegistration保存watch事件——>将请求封装成Packet并放入一个队列等待发送——>调用SendThread中的readResponse——>ZKWatchManager将该watch事件进行存储

//Zookeeper.java
    public byte[] getData(String path, Watcher watcher, Stat stat) throws KeeperException, InterruptedException {
   
   
        PathUtils.validatePath(path);
        ZooKeeper.WatchRegistration wcb = null;
        if (watcher != null) {
   
   
        	//注册watch
            wcb = new ZooKeeper.DataWatchRegistration(watcher, path);
        }

        String serverPath = this.prependChroot(path);
        RequestHeader h = new RequestHeader();
        h.setType(4);
        GetDataRequest request = new GetDataRequest();
        request.setPath(serverPath);
        request.setWatch(watcher != null);
        GetDataResponse response = new GetDataResponse();
        ReplyHeader r = this.cnxn.submitRequest(h, request, response, wcb);
        if (r.getErr() != 0) {
   
   
            throw KeeperException.create(Code.get(r.getErr()), path);
        } else {
   
   
            if (stat != null) {
   
   
                DataTree.copyStat(response.getStat(), stat);
            }

            return response.getData();
        }
    }
public ReplyHeader submitRequest(RequestHeader h, Record request, Record response, WatchRegistration watchRegistration, WatchDeregistration watchDeregistration) throws InterruptedException {
   
   
        ReplyHeader r = new ReplyHeader();
        ClientCnxn.Packet packet = this.queuePacket(h, r, request, response, (AsyncCallback)null, (String)null, (String)null, (Object)null, watchRegistration, watchDeregistration);
        synchronized(packet) {
   
   
            while(!packet.finished) {
   
   
                packet.wait();
            }

            return r;
        }
    }
    public ClientCnxn.Packet queuePacket(RequestHeader h, ReplyHeader r, Record request, Record response, AsyncCallback cb, String clientPath, String serverPath, Object ctx, WatchRegistration watchRegistration, WatchDeregistration watchDeregistration) {
   
   
        ClientCnxn.Packet packet = null;
        packet = new ClientCnxn.Packet(h, r, request, response, watchRegistration);
        packet.cb = cb;
        packet.ctx = ctx;
        packet.clientPath = clientPath;
        packet.serverPath = serverPath;
        packet.watchDeregistration = watchDeregistration;
        synchronized(this.state) {
   
   
            if (this.state.isAlive() && !this.closing) {
   
   
                if (h.getType() == -11) {
   
   
                    this.closing = true;
                }

                this.outgoingQueue.add(packet);
            } else {
   
   
                this.conLossPacket(packet);
            }
        }

        this.sendThread.getClientCnxnSocket().packetAdded();
        return packet;
    }
    class SendThread extends ZooKeeperThread {
   
   
        .....
        void readResponse(ByteBuffer incomingBuffer) throws IOException {
   
   
            ByteBufferInputStream bbis = new ByteBufferInputStream(incomingBuffer);
            BinaryInputArchive bbia = BinaryInputArchive.getArchive(bbis);
            ReplyHeader replyHdr = new ReplyHeader();
            replyHdr.deserialize(bbia, "header");
            if (replyHdr.getXid() == -2) {
   
   
                if (ClientCnxn.LOG.isDebugEnabled()) {
   
   
                    ClientCnxn.LOG.debug("Got ping response for sessionid: 0x" + Long.toHexString(ClientCnxn.this.sessionId) + " after " + (System.nanoTime() - this.lastPingSentNs) / 1000000L + "ms");
                }
            } else if (replyHdr.getXid() == -4) {
   
   
                if (replyHdr.getErr() == Code.AUTHFAILED.intValue()) {
   
   
                    ClientCnxn.this.state = States.AUTH_FAILED;
                    ClientCnxn.this.eventThread.queueEvent(new WatchedEvent(EventType.None, KeeperState.AuthFailed, (String)null));
                }

                if (ClientCnxn.LOG.isDebugEnabled()) {
   
   
                    ClientCnxn.LOG.debug("Got auth sessionid:0x" + Long.toHexString(ClientCnxn.this.sessionId));
                }

            } else if (replyHdr.getXid(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值