Watcher 实现机制之客户端注册

Zookeeper 提供的了分布式数据的发布/订阅功能,通过 Watch 机制来实现这种分布式的通知功能。

Zookeeper 允许客户端向服务器注册一个Watch监听,当服务端的一些指定的事件触发了这个Watch ,就会向指定的客户端发送一个事件通知来实现分布式通知。
整个Watch的注册和通知过程如图:
Zookeeper的 Watcher 机制主要包括客户端现成、客户端 WatchManager、Zookeeper服务器三部分,具体流程是:client 向Zookeeper注册的同时,把Watcher对象存储在客户端的WatchManager中,当Zookeeper服务器端触发Watcher事件后,会向客户端发送通知,客户端线程从WatchManager中取出对应的Watcher对象执行回掉逻辑。

客户端注册Watcher
可用在创建一个客户端实例时,向构造方法中传入一个默认的Watcher对象,也可以在调用 getData() , getChildren() , exist() 三个接口向 Zookeeper 服务器注册Watcher,无论使用哪种方式注册,原理都是一致的。 这里已 getData接口说明:

public byte[] getData(final String path, Watcher watcher , Stat stat) 

在向 getData 接口注册 Watcher 后,客户端首先会对当前客户端请求   request 进行标记,将其置为“使用 Watcher监听”,同时会封装一个 Watcher 的注册对象 WatcherRegistration 对象,用于暂时保存数据节点路径和Watcher的对应关系,具体逻辑代码:

public Stat getData(final String path, Watcher watcher , Stat stat){
     ..........
     WatcherRegistration wrt = null ;
     if(watcher !=null){
          wrt = new DataWatchRegistration(watcher,path);
     }
     ......
      request.setWatche(watcher!=null)  ;//------注意此处后续会用到
     ReplyHeader r = cnxn.submitRequest(h,request,response,wrt);

在Zookeeper中,Packet 可以被看做是一个最小的通信协议单元,用于客户端和服务器端之间进行网络传输,任何一个需要传输的对象都要被包装成   Packet  对象进行传输。因为 ClientCnxn 中的 WatcherRegistration 又会被封装到 Packet 中去,然后放入发送队列中等待客户端发送。

Packet queuePacket(RequestHeader h , ReplyHeader r , Record reqest , Record response, AsyncCallback cb ,String clientPath , String serverPath , Object ctx , WatcherRegistration wrt){
     .......
     synchronized(outgoingqueue){
          packet = new Packet(h,r,request,response,wrt) ;
          .........
          outgoingqueue.add(packet);
     }
....
}

随后,Zookeeper 客户端会向服务端发送这个请求,同时等待服务端的返回。完成请求发送后,会由客户端 SendThread 线程的 readResponse 方法接受来自服务端的响应,finishPacket 方法会从 Packet 中取出对应的 Watcher 并注册到ZkManager中去,代码逻辑:
     
private void finishPacket(Packet p){
     if(p.watcherRegistration != null){
          p.watcherRegistration.register(p.replyHeader.getErr());
     }
.......
}

现在把 Watcher 对象从 WatchRegistration 对象中取出来:
     
protected Map<String,HashSet<Watcher>> getWatchers(int rc){
     
     return watchManager.dataWatches ;

}

public void register(int rc){
     if(shouldAddWatch(rc)){
          Map<String,HashSet<Watcher>> watches = getWatchers(rc) ;
  synchronized(watches){
     
     Set<Watcher> watchers = watches.get(clientPath) ;
     if(watchers ==null){
            watchers  =new HashSet<Watcher>();
            watches.put(clientPath,watchers);
   }
             watchers. add(watcher);
     .........
}
在上面的register 方法中会吧暂时存放的 watcher 对象转交给 ZKWatcherManager , 并最终保存到dataWatchers 中 ,dataWatchers , ZKWatcherManager 都是 Map<String,Set<Watcher>> 类型的数据结构,用于把数据节点的路径和Watcher对象一一映射后保存起来。
   

在上面的流程中,WatcherRegistration 在底层的网络序列化到底层的字节数组中。
















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Watcher机制是ZooKeeper分布式协调服务中的一项重要功能。它允许客户注册对ZooKeeper节点的变化事件进行监听,并在节点状态发生变化时得到通知。 客户可以通过在创建、更新或删除节点时设置Watcher注册对节点变化事件的监听。一旦节点状态发生变化,例如节点被创建、更新或删除,ZooKeeper会通知相关的客户客户可以在收到通知后执行相应的处理逻辑,如重新获取节点数据或重新注册WatcherWatcher的一致性保证是通过ZooKeeper的副本机制实现的。ZooKeeper将节点状态的变化操作分为两个阶段,即leader服务器广播和follower服务器确认。只有当大多数服务器(即过半数)确认了状态变化操作时,Watcher才会被触发通知给客户。这样可以保证在分布式环境下的一致性。 容错处理是指当客户与ZooKeeper服务器之间的连接发生故障时,Watcher机制如何处理。当客户与服务器的连接断开时,ZooKeeper会将Watcher标记为“已过期”,并且不再向客户发送任何通知。客户可以通过重新连接到ZooKeeper服务器来重新注册Watcher,并继续监听节点变化事件。 需要注意的是,Watcher机制并不能保证实时性,即节点状态的变化可能不会立即被通知给客户。此外,Watcher通知是一次性的,即一旦触发通知后,客户需要重新注册Watcher才能继续监听节点变化事件。 希望以上对你有所帮助,如果有更多问题可以继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值