ZooKeeper监视(Watches)-时刻关注znode的变化
摘自《apache zookeeper essentials》
通常客户端访问该服务是通过轮询或者是拉取的模式,在大型的复杂的分布式系统中,使用拉取模式会遇到可扩展性的问题。为了解决这个问题,ZooKeeper的设计者们实现了这样的一种机制,客户端可以获取ZooKeeper Service
而不是通过轮询的方式,这很像推送的模式,从ZooKeeper service
将通知推送到已注册的客户端
已经注册到ZooKeeper service
的客户端可以获悉任何一个结点的变化。注册,用ZooKeeper Service
的术语叫做开启对一个znode的监视,监视意味着当znode发生变化时,客户端可以得到通知。监视是一次性(one-time
)的动作,也就是只能触发一次通知。如果要继续的接收到通知,客户端必须要注册监视
举个例子:
- 在集群环境下,一个结点
client1
,对新加进到集群的其他结点,要得到通知。任何加进集群中的中的结点都会在Zookeeper的/members
路径下创建一个短暂型(ephemeral)znode - 现在,另一个结点
client2
,加入到了集群,并在/members
路径下创建了一个短暂型(ephemeral)znode为host2
client1
对ZooKeeper
的/members
路径发送一个getChildren
的请求,并开启监视,当client2
创建了/members/host2
的znode之后,监视被触发,并且client1
发送的getChildren
请求现在可以看见host2
了
ZooKeeper
监视是一次性触发的,也就是说,当客户端接收过监视事件,并且想得到未来变化的通知,它必须设置其他的监视,Watches
是由客户端所连接的ZooKeeper
服务器维护的,这使得事件通知更快,更精益
当znode发生以下三个变化时监视才会被触发:
- znode结点上数据变化时,如通过
setData
方法将数据写入znode的data
域中 - znode的孩子结点发生变化时,如通过
delete
操作删除znode的孩子结点 - 创建或删除znode结点
ZooKeeper就通知和监视有以下保证:
- ZooKeeper保证监视以FIFO(先进先出)的方式保持有序,而且通知也是有序的被转发
- 对于相同的结点znode,监视通知总是先早于这个结点的其他变化
- 监视事件的顺序是针对
ZooKeeper Service
发现的更新进行排序的
录客户端与Zookeeper服务器断开连接,只有重新连接,客户端才能接收到监视,如果重新连接到服务器,所有之前注册的监视会重新会再次被注册和触发。如果客户端连接到了一个新的服务器,监视会被任何session事件所触发。与服务器的断开连接和重新连接到新的服务器对于客户端应用程序是透明的
如何设置监视:
通过stat
命令:
[zk: localhost:2181(CONNECTED) 0] ls /
[persistent_sequential0000000005, hello, zookeeper, root]
[zk: localhost:2181(CONNECTED) 1] create /master "lock"
Created /master
[zk: localhost:2181(CONNECTED) 2] stat /master true
cZxid = 0x1e
ctime = Sat Jul 14 08:45:00 UTC 2018
mZxid = 0x1e
mtime = Sat Jul 14 08:45:00 UTC 2018
pZxid = 0x1e
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
[zk: localhost:2181(CONNECTED) 3] create /master "lock again"
Node already exists: /master
[zk: localhost:2181(CONNECTED) 4] delete /master
WATCHER::
WatchedEvent state:SyncConnected type:NodeDeleted path:/master