ZK Exists Watch 和 Disconnect event
本篇博客信息主要参考书籍, zookeeper ,记录的主要是书中涉及到的一个zookeeper的特殊实例,博主也在工作中遇到了这个问题,特此翻译记录
正常情况下,当一个client 连接到zookeeper 的ensember(假设包含节点server1,server2,server3)后,假设一开始client连接了节点server1,并且设置了若干watch,再之后连接断开,但是client 在session timeout之后成功连接到了server2. 这时候,先前设置在各个节点上的watcher会被重新记录,如果断开期间有触发watcher,会在成功连接到server2 之后再次触发。
但是有个cornor case。就是,如果我们的client watch了一个exist 事件,用于检测这个节点什么时候被成功创建,
如果client在断开期间,有另外一个clientB 先创建了这个节点,然后又在client重新连接到server2 之前,又一次删除了这个节点。这种情况下,client的exist watch 就会完全无感知。
(反过来,如果client watch了一个exist 事件,用于检测某个已存在节点时候被删除是没有问题的。)
原理如下:
为了更加无缝的处理zookeper连接断开的问题,zookeeper的client sdk会在断开重连后,同时把已有的watches设置到新的zookeeper 节点上。主要就是因为zookeeper sdk会把watches和最近的zxid一并发布到
新的zookeeper server节点上。这时候,新连接的zookeeper节点会在建立连接的时候会把最新的timestamp和client传上来的last zxid进行对比,如果发现这些被watch的znodes存在有修改,并且修改介于last zxid和server latest 修改 timestamp,就会触发这些watch
这个逻辑对于非exists的watch工作的非常完美。但是exists操作的特异之处就是当它用于检测节点从无到有的情况下,由于断开期间,此被watch节点有可能先建立,马上又删除,节点不存在的情况下,zookeeper也就无法利用zxid进行watcher的补足,导致watcher漏触发。这种情况下, zookeeper只能保证重新连接新服务器后,将这个watch注册上去,期间的触发就会被丢失了。
由于这个conner case 很容易被忽略,建议少使用exists watch 来检测节点的建立事件。如果一定要用,也建议这个被检测的节点在建立后不会被删除。防止出现这种conner case。