zookeeper watcher功能分析
来源:互联网 发布:lol进游戏无法连接网络 编辑:程序博客网 时间:2024/06/05 00:51
0. 总述
All of the read operations in ZooKeeper - getData(), getChildren(), and exists() - have the option of setting a watch as a side effect. Here is ZooKeeper's definition of a watch: a watch event is one-time trigger, sent to the client that set the watch, which occurs when the data for which the watch was set changes。
getData,getChildren(),exists()这三个方法可以针对参数中的path设置watcher,当path对应的Node 有相应变化时,server端会给对应的设置了watcher的client 发送一个一次性的触发通知事件。客户端在收到这个触发通知事件后,可以根据自己的业务逻辑进行相应地处理。
注意这个watcher的功能是一次性的,如果还想继续得到watcher通知,在处理完事件后,要重新register。
1. 客户端
1)黄色部分表示处理Watcher功能
2)绿色部分表示nio处理中一个数据结构的封装
3)蓝色部分表示通过nio请求,接收数据的处理类
请求的处理流程:
下面以 public byte[] getData(final String path, Watcher watcher, Stat stat)接口为例进行说明:
1. 在有Watcher的情况下,
对照右上图的类图,把watcher,path包装成一个DataWatchRegistration对象。整个WatchRegistration的结构主要是利用了继承的多态性,不同子类的getWatches方法返回不同的结果集,而这些对调用方是屏蔽的。
2. 构造请求头
不同方法请求头的主要区别是type不一样
3. 构造request,reponse
从类图中也可以看出,不同的方法对象于不同的request,response对象,对getData方法来说,是对应于 GetDataRequest,GetDataResponse。
GetDataRequest对象中的属性是:path,以及一个boolean值 watch用来表示这个请求是否有watch。
4. 构造响应头
这时候,ReplyHeader还是一个空对象,这里的内容要等nio返回内容时进行填充。
5. 构造 Packet对象
包含:RequestHeader,ReplyHeader,request,response, watchRegistration
在这里把 requestHeader,request对象进行序列化,放入packet对象的Bytebuffer属性中。
而replyHeader,response对象目前都是空,内容要等nio返回内容,解释出Bytebuffer中内容进行填充。
同时在一开始就构造的DataWatchRegistration对象赋值给packet对象中的watchRegistration属性,这属性会在收到packet对象时有作用,下面再介绍。
6. packet对象准备好后,把整个对象放入一个outgoingQueue:LinkedList中,就等着通过nio把packet对象中byteBuffer中的内容发送给server端面。之所以使用LinkedList,是因为它提供了操作头,尾的方法。
7. packet被放入outgoingQueue中,等待SendThread把packet对应的内容发送给server。
8.如果是带callback的异步调用,则整个调用过程就结束,如果是同步调用的话,判断packet的finished状态是否为true,如果为false,进行wait,等待nio得到response后,把packet的状态改成finished为true,调用notify通知当前等待。
后续NIO操作,和server进行数据传输就交给专门的SendThread来处理。
整个nio主要是是围绕Selector,SocketChannel,SelectionKey,ByteBuffer这四个对象进行操作。
在这里围绕主流程来描述:
1. 当SelectionKey 处于isWritable状态时
A。从 outgoingQueue中取出一个packet中的byteBuffer内容,写入socketChannel。
B。从outgoingQueue中remove 第一个packet,
C。如果这个packet对应的头不是ping, auth类型,把这个packet放入pendingQueue。因为这两个请求的返回不需要额外处理,因此也就不需要放在等待返回的对列中。 pendingQueue的作用就是:因为采用了NIO返回是异步的,当结果返回时,要能找到原来请求的对象,所以要维护这么一个列队来保存已经被发送,但还没收到返回的Packet对象。
响应的流程分析
响应的数据类型:
sendthread接收来自server的response类型:
1)针对心跳的ping请求的resp
2)针对auth请求的resp
3)一般接口请求的resp
4)如果接口请求要求了watcher,当watcher关注的内容有变化时的notification
一般接口请求的resp处理:
1) 判断从ByteBuffer中反序列化出来的replyHeader中的xid和 pendingQueue中第一个packet维护的xid是否相同。Zookeeper是保证发发送的packet会发收到response,在这里是对这个有序性进行验证。
2) 反序列化出 response对象的内容。
3) 这个时候已经拿到了packet的响应内容,但为了对callback,watcher功能的支持,还需要额外的处理:
4) A:如果这个packet包含了watcher,将这个请求对象的watcher注册到watcherManager,这是为了当针对watcher的notification响应到达的时候,能找到对应的watcher。
5) B: 如果接口是同步调用的话,这时设置packet的finished为ture,并且通过notify进行通知。
6) C: 如果是带callback的异步调用,则将packet放入eventThread,让eventThread异步调用callback接口。
针对watcher对应notification的resp处理
如果sendthread分析出当前的response是针对watcher的notification,
1) 将reponse反序列化成WatcherEvent
2) WatcherEvent转化成WatchedEvent
3) 之前说过如果请求带watcher,在返回时,会在watcherManager中注册对应的watcher。当收到WatchedEvent后,就可以根据event的数据从watcherManger中取到对应的watcher集合。
4) 将WatchedEvent和对应的watcher集合封装成WatcherSetEventPair
5) WatcherSetEventPair放入eventThread中的waitingEvents列表
6) eventthread在run循环中,取中WatcherSetEventPair,调用其中的watcher接口。
二、 服务端针对watcher设计
zookeeper的数据模型如下:
按照经验,在server端 应该设计成这样:
1) 应该有一个domain来 对应这个数据模型
2) domain中 包含了一些监听对象,也就是说在某个node上修改数据时,要调用相应的各类监听对象,把此node的数据被修改的事件告诉监听对象,至于 监听对象想做些什么操作,应该由它自己来决定,这点应该和这个domain无关。根据One-time trigger的特性,这些监听对象被触发后需要被 remove掉。
3) 这些监听对象应该在client调 用getData(),getChildren(),exits()方法时,register在domain中。
实际实现:
DataTree 来表示整个数据模型,其中包含了WatchManager,
当有node数 据变更,node增加,删除时,调用 triggerWatch方法,根据path来判断是否有对应的watcher,如果有watcher,依次调用这些watcher的process方 法。
注意这里的watcher并不是客户端通过getData()等方法register的watcher。而是server端的 NIOServerCnxn,这类是在server端 实现Watcher接口。在实现上是每个客户端连接一个NIOServerCnxn。 当客户端请求的request中watcher参 数为true时,在server端把NIOServerCnxn注册到watcherManager。
process接口的实现很简单,
ReplyHeader h = new ReplyHeader(-1, -1L, 0);
if (LOG.isTraceEnabled()) {
ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,
"Deliver event " + event + " to 0x"
+ Long.toHexString(this.sessionId)
+ " through " + this);
}
// Convert WatchedEvent to a type that can be sent over the wire
WatcherEvent e = event.getWrapper();
//6+1 10-07-04
System.out.println("****server 6+1:"+event.getType());
sendResponse(h, e, "notification");
1)首先构造响应头,这里xid,zxid都 是固定的-1,用来表示这是一个event reply。
2)把接口中的WatchedEvent对 象转换成WatcherEvent,这是因为WatchedEvent中 使用了enum,直接转换成 int.
3)把reply header, WatcherEvent写入输入流。replyheader的作 用是让client来判断当前是接收的是一般的packet还 是event通 知,WatcherEvent包 含了事件的类型,因为我们知道process接口中是 WatchedEvent对象,因此可以肯定client在拿到WatcherEvent对象后,还要还原回来的WatchedEvent。 再调用在 client中存在的Watcher实 现类。
个人总结:
1) 在使用nio进行异步通信时,有一个队列:sendingQueue来存放当前请求的packet,设计一个和server通信的线程,当socketChannel可写的时候,从队列出取出packet,发送给server。为了当server返回请求结果时,能找到原来的packet,还需要有一个pendingQueue来存放已对发送给server但还没有接收到 response的 packet。简单来说就是一个负责通信的Thread外加两个队列的配合来完成发送请求,接收响应的业务。
2) 如果需要像zookeeper一样设计watcher功能,则需要在client有一个watcherManager来存放对应请求关心的watcher,当packet正常返回时,把watcher注册到manager中去,等watch事件触发时,能有地方找到对应的watcher,并调用规定的接口。
3) Server端对watch事件的触发,和平时经常遇到的listener事件触发是一模一样的:实现一个事件总的管理类:listenerManager,它包含了各个listener。在需要关心的接口调用地方,增加调用事件管理类的接口,比如:process()。具体对这个事件有什么操作,由事件管理类中的各个listener自己去实现。
4) 为了事件处理的异步,zookeeper另外设计了EventThread,当SendThread在分析response时得知可以异步处理时,把数据封装成一个特定对象交给EventThread。
5) 所谓的异步callback,异步watcher都可以在同步实现中找到影子:如spring中的对ibatis,hibernate进行封装提供的callback功能,listener事件管理的设计。
- zookeeper watcher功能分析
- zookeeper watcher功能分析
- zookeeper watcher功能分析
- Zookeeper--Watcher
- ZooKeeper Watcher执行顺序
- ZooKeeper Watcher执行顺序 ********************
- ZooKeeper watcher和version
- zookeeper Watcher API 说明
- ZooKeeper Watcher注意事项
- zookeeper的watcher示意图
- zookeeper之watcher机制
- zookeeper的watcher相关
- ZooKeeper Watcher代码实例
- Zookeeper的Watcher
- zookeeper学习心得三:Watcher
- ZooKeeper Watcher注意事项
- Zookeeper的watcher
- zookeeper通知watcher
- poj 2406 Power Strings
- HDU 1707 Spring-outing Decision(输出课程表是否与假期冲突)
- 黑马程序员—修改各个文件夹下的文件的后缀名
- java.lang.OutOfMemoryError: PermGen space
- VS中的 MD/MT设置
- zookeeper watcher功能分析
- java测试请求网站返回的状态码
- Crofter's加拿大进口克拉夫特草莓果酱283g USDA有机认证非转基因
- 运行时存储空间的组织和管理
- 最短路径问题 hdu acm c++
- AJAX技术使用XMLHttpRequest对象传递参数的中文乱码问题
- 多重继承下,不同基类指针指向同一子类对象的地址问题——腾讯一笔试题
- jsp返回xml浏览器解析错误问题解决方法
- ACM 109. [NOIP2004] 合唱队形(dp+枚举)