zookeeper主要是为了统一分布式系统中各个节点的工作状态,在资源冲突的情况下协调提供节点资源抢占,提供给每个节点了解整个集群所处状态的途径。这一切的实现都依赖于zookeeper中的事件监听和通知机制。
zookeeper中的事件和状态
事件和状态构成了zookeeper客户端连接描述的两个维度。这里我们通过下面的两个表详细介绍zookeeper中的事件和状态。
zookeeper客户端与zookeeper server连接的状态
连接状态 | 状态含义 |
---|---|
KeeperState.Expired | 客户端和服务器在ticktime的时间周期内,是要发送心跳通知的。这是租约协议的一个实现。客户端发送request,告诉服务器其上一个租约时间,服务器收到这个请求后,告诉客户端其下一个租约时间是哪个时间点。当客户端时间戳达到最后一个租约时间,而没有收到服务器发来的任何新租约时间,即认为自己下线(此后客户端会废弃这次连接,并试图重新建立连接)。这个过期状态就是Expired状态 |
KeeperState.Disconnected | 就像上面那个状态所述,当客户端断开一个连接(可能是租约期满,也可能是客户端主动断开)这是客户端和服务器的连接就是Disconnected状态 |
KeeperState.SyncConnected | 一旦客户端和服务器的某一个节点建立连接(注意,虽然集群有多个节点,但是客户端一次连接到一个节点就行了),并完成一次version、zxid的同步,这时的客户端和服务器的连接状态就是SyncConnected |
KeeperState.AuthFailed | zookeeper客户端进行连接认证失败时,发生该状态 |
需要说明的是,这些状态在触发时,所记录的事件类型都是:EventType.None。
zookeeper中的watch事件(当zookeeper客户端监听某个znode节点”/node-x”时)
zookeeper事件 | 事件含义 |
---|---|
EventType.NodeCreated | 当node-x这个节点被创建时,该事件被触发 |
EventType.NodeChildrenChanged | 当node-x这个节点的直接子节点被创建、被删除、子节点数据发生变更时,该事件被触发。 |
EventType.NodeDataChanged | 当node-x这个节点的数据发生变更时,该事件被触发 |
EventType.NodeDeleted | 当node-x这个节点被删除时,该事件被触发。 |
EventType.None | 当zookeeper客户端的连接状态发生变更时,即KeeperState.Expired、KeeperState.Disconnected、KeeperState.SyncConnected、KeeperState.AuthFailed状态切换时,描述的事件类型为EventType.None |
watcher的特性
一次性:
对于ZK的watcher,只需要记住一点:zookeeper有watch事件,是一次性触发的,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher,由于zookeeper的监控都是一次性的,所以每次必须设置监控。
客户端串行执行:
客户端Watcher回调的过程是一个串行同步的过程,这为我们保证了顺序,同事需要开发人员注意一点,千万不要因为一个Watcher的处理逻辑影响了整个客户端的Watcher回调。
轻量:
WatchedEvent 是Zookeeper整个Watcher通知机制的最小通知单元,整个结构只包含三部分:通知状态、事件类型和节点路径。也就是说Watcher通知非常的简单,只会告诉客户端发生了事件,而不会告知其具体内容,需要客户端自己去进行获取,比如NodeDataChanged事件,Zookeeper只会通知客户端指定节点的数据发生了变更,而不会直接提供具体的数据内容。
watcher原理框架
由图看出,zk的watcher由客户端,客户端WatchManager,zk服务器组成。整个过程涉及了消息通信及数据存储。
- zk客户端向zk服务器注册watcher的同时,会将watcher对象存储在客户端的watchManager。
- Zk服务器触发watcher事件后,会向客户端发送通知,客户端线程从watchManager中回调watcher执行相应的功能。
注意的是server服务器端一般有多台共同一起对外提供服务的,里面涉及到zk专有的ZAB协议(分布式原子广播协议)。因为ZAB协议是zookeeper的实现精髓,有了zab协议才能使zk真正落地,真正的高可靠,数据同步,适于商用。
Zookeeper Watcher的运行机制
1,Watch是轻量级的,其实就是本地JVM的Callback,服务器端只是存了是否有设置了Watcher的布尔类型。(源码见:org.apache.zookeeper.server.FinalRequestProcessor)
2,在服务端,在FinalRequestProcessor处理对应的Znode操作时,会根据客户端传递的watcher变量,添加到对应的ZKDatabase(org.apache.zookeeper.server.ZKDatabase)中进行持久化存储,同时将自己NIOServerCnxn做为一个Watcher callback,监听服务端事件变化
3,Leader通过投票通过了某次Znode变化的请求后,然后通知对应的Follower,Follower根据自己内存中的zkDataBase信息,发送notification信息给zookeeper客户端。
4,Zookeeper客户端接收到notification信息后,找到对应变化path的watcher列表,挨个进行触发回调。
参考:
https://blog.csdn.net/weixin_35720385/article/details/100561701