目录
Zookeeper模型分成数据模型,节点特性,版本,Watcher,ACL五个部分。
1 数据模型
- 树形结构:每个节点成为ZNode,是数据的最小单元,每个节点可以存放数据或者是子节点。
- 事务ID:ZXID,每次对服务器状态进行操作(节点创建与删除;节点内容更新;客户端会话与失效),就会分配全局的事务ID
2 节点类型
根据节点生命周期长短分成持久节点,临时节点,顺序节点
- 持久节点:一直存在服务端,直到手动删除。
- 临时节点:生命周期是客户端的会话失效周期,不是TCP断开连接。临时节点只能作为叶子节点,不能基于临时节点创建子节点。
- 顺序节点:节点可能还表现为顺序特性,即节点在父节点列表中是否标记创建顺序。
3 状态信息
节点信息包含节点数据内容以及状态信息。
- czxid:reated ZXID,表示该节点被创建时的事务ID
- mzxid:Modified ZXID,表示该节点最后一次被更新时的事务ID
- ctime:表示节点被创建的时间
- mtime:表示该节点最后一次被更新时的时间
- version:数据节点的版本号。节点被创建后,被更新过的次数,即使更新的内容与原内容相同,也视为一次更新
- cversion:子节点的版本号
- aversion:节点的ACL版本号
- ephemeralOwner:创建该临时节点的会话的SessionID。如果该节点为持久节点,那么这个属性值为0
- dataLength:数据内容的长度
- numChildren:当前节点的子节点个数
- pzxid:表示该节点的子节点列表最后一次被修改时的事务ID。只有子节点列表变更了才会变更pzxid,子节点内容变更不会影响pzxid
4 Watcher机制
一对多的发布订阅模式,客户端向服务端注册watcher,监听某一特定主题的对象,当主题对象自身发生变化时,会通知所有的订阅者。
4.1 Watcher基础
Watcher机制的对象包括:
- 客户端线程
- 客户端WatcherManager
- 服务端
Watcher机制:
- 客户端向服务端注册watcher同时会把watcher对象存入客户端WatcherManager中
- 当服务端触发Watcher事件后,服务端会向客户端发送通知
- 客户端线程从WatcherManager中取出对应的Watcher对象,执行回调逻辑。
Watcher特性包含:
- 注册一次性。watcher一旦被触发,就会被删除。如果需要监听,就要手动注册。否则一些更新比较频繁的节点,每次变动都要不断地将通知反馈给客户端,对与网络以及服务端性能影响很大。
- 客户端Watcher回调是串行同步的,保证了每个wathcer的顺序。
- 轻量级watcher。WatchedEvent是Watcher机制的最小通知单元,只包含了通知状态,事件类型,节点路径,不给出具体的变化内容,需要客户端自己去相应节点获取变化的内容,保证了客户端服务端交互的数据量级。
4.2 Watcher事件
Watcher通知状态与事件类型
注意:
- NodeDataChanged:与dataVersion一致,即使变更内容前后一样,也会触发此事件。
- NodeChildrenChanged:所关注的节点的子节点列表有变化。这里说的变化是指子节点的个数和组成,具体到子节点内容的变化是不会通知的。
4.3 process回调方法
WatchedEvent包含三个属性:事件状态keeperstate,事件类型EventType,节点路径path。
abstract public void process(WatchedEvent event);
WatcherEvent与WatchedEvent:
- WatchedEvent表示服务端与客户端之间的逻辑对象
- WatcherEvent实现了序列化接口,可用于网络传输
- 服务端生成WatchedEvent后调用getWrapper方法包装成可序列化的WatcherEvent事件,以便传输到客户端;客户端接到后将WatcherEvent转换成WatchedEvent,使用process进行处理
4.4 Watcher工作机制
watcher注册机制包括:
- 客户端注册Watcher
- 服务端处理Watcher
- 客户端回调Watcher
4.4.1 客户端注册Watcher
/**
*/
public interface ClientWatchManager {
/**
* Return a set of watchers that should be notified of the event. The
* manager must not notify the watcher(s), however it will update it's
* internal structure as if the watches had triggered. The intent being
* that the callee is now responsible for notifying the watchers of the
* event, possibly at some later time.
*
* @param state event state
* @param type event type
* @param path event path
* @return may be empty set but must not be null
*/
public Set<Watcher> materialize(Watcher.Event.KeeperState state,
Watcher.Event.EventType type, String path);
}
关键类
- ZooKeeper:客户端基础类、存储了ClientCnxn和ZkWatcherManager
- ZKWatchManager:ZooKeeper的内部类,实现了ClientWatchManager接口,主要用来存储各种类型的Watcher,主要有三种:dataWatches、existWatches、childWatches以及一个默认的defaultWatcher。
- ClientCnxn:与服务端的交互类,主要包含以下对象:outgoingQueue、SendThread和EventThread。
- 其中outgoingQueue未待发送给服务端的Packet列表,
- SendThread线程负责和服务端进行请求交互
- EventThread线程则负责客户端Watcher事件的回调执行
- WatchRegistration:Zookeeper的内容类,包装了Watcher和clientPath,并且负责Watcher的注册
- Packet:ClientCnxn的内部类,与Zookeeper服务端通信的交互类
客户端处理步骤:
- 创建zk客户端对象实例时注册watcher,这个 Watcher 将作为整个 ZooKeeper 会话期间的默认 Watcher,它会一直被保存在客户端
ZKWatchManager
的defaultWatcher
里面。(getData, getChildren, exists方法中也可以注册watcher) - 例如getData注册Watcher后,客户端会向当前的request标记,设置为“使用watcher监听”,同时封装WatcherRegistration对象用于暂时保存数据节点路径和wathcer对应关系。
- WatchRegistration被封装成Packet对象,放入发送队列等待客户端发送。客户端没有把Watcher对象发送给服务端,只是将request与requestHeader两个属性序列化传输,否则服务端就容易出现内存紧张甚至溢出的危险。
- ZKWatcherManager.dataWatches是Map<String, Set>保存数据节点路径与Watcher对象关系。
4.4.2 服务端处理Watcher
对于注册 Watcher 请求,FinalRequestProcessor 的 ProcessRequest 方法会判断当前请求是否需要注册 Watcher,如果为 true,就会将当前的 ServerCnxn 对象和数据节点路径传入 getData 方法中去。ServerCnxn 是一个 ZooKeeper 客户端和服务器之间的连接接口,代表了一个客户端和服务器的连接,我们后面讲到的 process 回调方法,实际上也是从这里回调的,所以可以把 ServerCnxn 看作是一个 Watcher 对象。数据节点的节点路径和 ServerCnxn 最终会被存储在 WatchManager 的 watchTable 和 watch2Paths 中。
WatchManager 负责 Watcher 事件的触发,它是一个统称,在服务端 DataTree 会托管两个 WatchManager,分别是watchTable和 watch2Paths,分别对应数据变更 Watcher 和节点变更 Watcher。
当DataTree中节点数据内容或版本发生变化或节点变更时,会调用相应方法去触发 WatchManager 的 triggerWatch 方法,该方法返回 ZNODE 的信息,自此进入到回调本地 process 的序列。
4.4.3 客户端回调Watcher
SendThread的response()方法负责接收这个客户端事件通知。首先会对replyHeader中xid进行判断,如果是-1,则说明是一个通知类型的响应。作以下处理:
- 反序列化:ZooKeeper客户端接到请求后,首先将字节流转换成WatcherEvent对象。
- 处理chrootPath:如果客户端设置了chrootPath属性,那么需要对服务端传过来的完整的节点路径进行chrootPath处理,生成客户端的一个相对节点路径。
- 还原WatchedEvent:将WatcherEvent对象转换成WatchedEvent。
- 回调Watcher:将WatchedEvent对象交给EventThread线程,在下一个轮询周期中进行Watcher回调。
5 ACL保障数据安全
用于对节点的权限进行控制,一个有效的ACL信息包含:权限模式(Scheme),授权对象(ID),权限(Permission),即"scheme:ID:permission"。
参考
- https://www.cnblogs.com/shamo89/p/9787176.html
- 图比较详细,https://www.cnblogs.com/ZhuChangwu/p/11593642.html