美文网首页Zookeeper
Zookeeper之Watch机制源码分析

Zookeeper之Watch机制源码分析

作者: loveFXX | 来源:发表于2020-06-14 13:32 被阅读0次

    Zookeeper的Watch机制提供了服务通知功能,包含客户端的注册和触发、服务端的注册和触发


    image.png
    Zookeeper客户端:

    通过ZKWatchManager管理
    结构都是存储Map<String, Set<Watcher>>
    例如:{"/abc",Set<Watcher>} 表示/abc节点下绑定了Watcher有哪些
    1、临时的一次性的,用完即删除有dataWatches、existWatches、childWatches
    2、永久性的有persistentWatches、persistentRecursiveWatches(表示递归的永久性Watcher)

    Zookeeper服务端:

    有dataWatches和childWatches
    每个属性下面都有watchTable、watch2Paths。
    服务端的Watcher表示当前客户端的实现类NioServerCnxn
    watchTable:Map<String, Set<Watcher>>
    例如:{"/abc",Set<Watcher>} 表示/abc节点下有哪些客户端含有Watcher
    watch2Paths: Map<Watcher, Set<String>>
    例如:{Watcher,Set<String>} 表示当前客户端下有那些路径下有Watcher

    客户端注册

    当调用自定义getData方法时


    image.png

    1、getData
    这里并没有注册
    org.apache.zookeeper.ZooKeeper#getData


    image.png
    ①、把watcher和clientPath封装成DataWatchRegistration对象
    org.apache.zookeeper.ZooKeeper.DataWatchRegistration#DataWatchRegistration
    image.png

    org.apache.zookeeper.ZooKeeper.WatchRegistration#WatchRegistration


    image.png
    ②、提交请求submitRequest
    把封装的对象使用cnxn.submitRequest方法提交请求,最终把DataWatchRegistration wcb赋值给数据包Packet的watchRegistration属性
    image.png
    2、通过SendThread线程的readResponse读取响应数据
    ①、readResponse
    org.apache.zookeeper.ClientCnxn.SendThread#readResponse
    image.png
    ②、finishPacket
    org.apache.zookeeper.ClientCnxn#finishPacket
    image.png

    ③、register
    通过数据包的WatchRegistration属性值注册watch
    org.apache.zookeeper.ZooKeeper.WatchRegistration#register


    image.png
    org.apache.zookeeper.ZooKeeper.DataWatchRegistration#getWatches
    获取的是ZKWatchManager#dataWatches属性
    image.png
    最终把当前watch注册给了ZKWatchManager的dataWatches属性值。

    服务端注册

    服务端的注册是在请求处理链的最后一个请求处理类FinalRequestProcessor的processRequest方法来调用的
    客户端是以zooKeeper.getData方法来测试的,所以直接到getData
    org.apache.zookeeper.server.FinalRequestProcessor#processRequest


    image.png

    org.apache.zookeeper.server.FinalRequestProcessor#handleGetDataRequest


    image.png
    org.apache.zookeeper.server.ZKDatabase#getData
    image.png
    org.apache.zookeeper.server.DataTree#getData
    image.png

    org.apache.zookeeper.server.watch.WatchManager#addWatch


    image.png
    org.apache.zookeeper.server.watch.WatchManager#addWatch
    ①、watchTable
    Map<String, Set<Watcher>> 表示一个路径有多少个客户端Watcher(NioServerCnxn对象)
    image.png
    ②、watch2Paths
    Map<Watcher, Set<String>> 表示一个客户端Watcher(NioServerCnxn对象)有多少个路径
    image.png
    dataWatches和childWatches都是添加watchTable、watch2Paths的属性值
    dataWatches和childWatches是在DataTree创建对象时创建的,都属于IWatchManager对象
    image.png

    客户端触发

    是在SendThread线程读取响应readResponse时
    1、添加到waitingEvents队列
    NOTIFICATION_XID = -1 是触发WATCHER_EVENT
    ①、readResponse
    org.apache.zookeeper.ClientCnxn.SendThread#readResponse


    image.png
    image.png

    ②、queueEvent


    image.png
    org.apache.zookeeper.ClientCnxn.EventThread#queueEvent
    image.png
    把当前响应事件添加到waitingEvents队列中
    2、一次性Watch与持久Watch的区别
    在添加waitingEvents队列之前,调用materialize方法根据路径查找客户端的Watch
    org.apache.zookeeper.ZKWatchManager#materialize
    image.png
    image.png

    dataWatches把当前节点的watch给移除了,这就是为什么zooKeeper.getData方法的watch只能调用一次
    而持久化节点并没有移除


    image.png
    3、调用watch的process方法
    便可以调用到客户端自定义的监听watch的process方法
    org.apache.zookeeper.ClientCnxn.EventThread#run
    image.png
    org.apache.zookeeper.ClientCnxn.EventThread#processEvent
    image.png

    服务端触发

    服务端的触发也是在请求处理链的最后一个请求处理类FinalRequestProcessor的processRequest方法来调用的
    1、processRequest
    org.apache.zookeeper.server.FinalRequestProcessor#processRequest


    image.png

    2、applyRequest
    org.apache.zookeeper.server.FinalRequestProcessor#applyRequest


    image.png
    3、processTxn
    org.apache.zookeeper.server.ZooKeeperServer#processTxn(org.apache.zookeeper.server.Request)
    image.png
    4、processTxnInDB

    org.apache.zookeeper.server.ZooKeeperServer#processTxnInDB


    image.png
    5、processTxn
    org.apache.zookeeper.server.ZKDatabase#processTxn
    image.png
    org.apache.zookeeper.server.DataTree#processTxn
    image.png
    org.apache.zookeeper.server.DataTree#processTxn
    image.png
    org.apache.zookeeper.server.DataTree#processTxn
    image.png
    6、setData
    这里还是以/abc节点为例,开启一个客户端修改/abc的值。调用命令set /abc xxx。直接到setData
    这里可以看到修改前、修改后的数据、路径、zxid等信息

    org.apache.zookeeper.server.DataTree#setData


    image.png
    触发NodeDataChanged事件类型
    image.png
    7、triggerWatch
    org.apache.zookeeper.server.watch.WatchManager#triggerWatch
    image.png
    org.apache.zookeeper.server.watch.WatchManager#triggerWatch
    可以看到当前路径(/abc)下的上下文客户端对象
    image.png
    org.apache.zookeeper.server.watch.WatchManager#triggerWatch
    这里调用了递归的文件,最终的效果就是查找当前路径下的客户端对象
    image.png
    image.png
    遍历Watch对象的process方法
    image.png
    8、process
    org.apache.zookeeper.server.NIOServerCnxn#process
    image.png
    响应头设置ClientCnxn.NOTIFICATION_XID,这里与客户端读取响应头相对应
    9、sendResponse
    发送响应数据到客户端
    org.apache.zookeeper.server.NIOServerCnxn#sendResponse
    image.png
    EventType事件类型

    None、NodeCreated(节点创建)、NodeDeleted(节点删除)、NodeDataChanged(节点数据修改)、NodeChildrenChanged(孩子节点改变)、DataWatchRemoved(监听器Watch移除)、ChildWatchRemoved(孩子监听器Watch移除)、PersistentWatchRemoved(持久化的监听器Watch移除)


    image.png

    总结:

    根据客户端使用不同的API触发不同的监听器Watch。
    客户端的注册是在SendThread线程和触发是在EventThread线程
    服务端的注册和触发都是在请求处理链FinalRequestProcessor的processRequest方法内

    相关文章

      网友评论

        本文标题:Zookeeper之Watch机制源码分析

        本文链接:https://www.haomeiwen.com/subject/uoexxktx.html