1.zk的数据结构就像是一颗树,每个节点叫Znode,是zk数据结构中最小的数据结构,Znode可以保存数据,也可以在节点下再创建子节点。

2.ZXID 是事务ID,是一个64位的数字,是全局唯一的事务ID,可以体现事务的先后顺序,前32位是leader周期,后32位是递增顺序,每一个ZXID对应一次更新操作。

3.zk的节点有三大类,临时节点,持久节点,顺序节点。 这三种可以组合形成如下:

持久节点: 创建后会一直存在,直到有删除操作将其删除。
持久顺序节点:父节点会为其第一级子节点维护一份顺序性,创建子节点时候,会给节点名称后面自动加上一个数字后缀。这个数字的最大值是整型的最大值。
临时节点:临时节点的生命周期和客户端绑定,如果客户端会话失效,临时节点就会被清除。 zk规定了不能在临时节点
上创建子节点,临时节点只能作为叶子节点。
临时顺序节点:临时节点上加上了顺序的特性。

每个节点除了存储数据之外,还存储了这个节点的状态
czxid 节点创建时的事务id
mzxid最后一次更新时的事务id
ctime创建时间
mtime 最后一次创建时间
cversion 子节点版本号
aversion 节点的acl版本号
ephemeralOwner 创建该临时节点会话的sessionID,如果是持久节点 则为0
datalength 数据内容的长度,默认最大在1万字节的左右 ,也就是10kb
numchildren 当前节点的子节点个数
pzxid 表示该节点列表最后一次被修改时的事务id,也就是子节点数量变更时的zxid,子节点内容变更不会改变pzxid

版本 保证分布式数据库的原子性操作
版本表示的是节点内容或者acl信息或者子节点列表的修改次数,版本号为0表示修改次数为0 ,即使前后修改的内容都完全一致,次数也会加一

version 当前数据节点内容版本号
cversion 当前数据节点子节点的版本号
aversion 当前数据节点acl变更版本号

版本号用于乐观锁,在PrerequestProcessor处理器类中,在处理数据更新的时候
先取出当前setDataRequest请求的版本 的版本号
从数据记录记录中取出服务端最新的版本号
如果版本号不为-1 (-1表示不使用乐观锁)且 当前版本不等于服务端版本,那么就抛出异常

乐观锁原理:如果是符合期望的值,就更新,否则失败。cas 比较并更新

watcher机制
客户端向服务端注册一个watcher监听,当符合要求的事件触发了watcher,就会向指定客户端发送一个事件通知。

主要包括三个部分:
1.客户端线程
2.客户端watcherManager
3.zk服务器

客户端在向服务端注册watcher时,会把watcher对象存储在watcherManger中,当收到服务端的通知时,就去watcherManager中取出watcher对象执行其处理方法。

watcher事件中有通知状态和事件类型两个参数
事件状态 keepState :
syncConnected同步连接 有四种事件类型

Disconnected 断开链接 无事件类型
Expired 过期 无事件类型
authFaild 认证失败 无事件类型

事件类型eventType:
NodeCreate 节点创建
NodeDeleted 节点删除
NodeDataChanged 节点数据变更
NodeChildrenChangeed 子节点变更

以上都是可以触发watcher的事件

回调watcher接口时候,传入watcherEvent对象,该对象有三个参数,分别为事件状态 keepState ,事件类型eventType, 节点路径Path

分布式笔记(九)zookeeper技术内幕之数据结果和watcher机制

真实的watcher对象 里面封装了回调逻辑,存储在客户端的zkwatcherManager中,发送给服务端是一个标记
然后服务端发现有监听标记,就将这个和客户端交互的连接 也作为一个"watcher"保存在服务端的watchManager中。
服务端的watcherManger内有两个数据结构,分别是节点-watcher映射的 watcherTable和 wacther-节点 映射的watcher2Path。
当有改变节点的事务进来时,处理之后,就用这个节点去wachManger中找 ,如果有对应的wacher ,就取出来 ,因为存储的是一个链接,通过这个链接去通知客户端,客户端的sendThread收到通知,在zkwatcherManager中找到watcher,并将其移出,
并将其放到队列中, 另一个eventThread 会循环不断的从这个队列中取出来watcher 执行其process方法。

特点:
1.一次性
客户端 服务端 的watcher都是一次性的,这样设计可以减轻服务端的压力,因为针对更新非常频繁的节点,服务端会不断向客户端发送通知,会服务端和网络压力都会非常大
2.轻量级
发送给客户端的watcheEvent只包含了节点路径,事件类型,通知状态
发送给服务端的watcher 仅仅是一个标记,服务端存储的时候也是当前连接的serverCnxn对象。
3.客户端串行执行
eventThread不断的从队列中取出来watcher进行执行,因此需要注意的就是 不要在wacther的回调事件中做非常耗时的操作,
如果有必要,就传入一个线程池参数,会转给这个线程池完成

相关文章:

  • 2022-12-23
  • 2021-08-10
  • 2021-12-25
  • 2021-12-31
  • 2021-09-02
  • 2021-04-06
  • 2021-07-11
  • 2021-04-13
猜你喜欢
  • 2021-11-13
  • 2021-06-10
  • 2022-12-23
  • 2021-05-21
  • 2021-10-03
  • 2021-10-07
  • 2021-12-23
相关资源
相似解决方案