avatar

Zookeeper技术内幕

数据模型znode

zk数据存储结构与标准的unix文件系统非常相似,都是在根节点下挂很多子节点zk中没有引入传统文件系统中目录与文件的概念,而是使用了称为znode的数据节点概念。znodezk中数据的最小单元,每个znode上都可以保存数据挂载子节点,形成一个树形化命名空间。

znode

节点类型

  • 持久节点:zk中最常见的节点,节点一旦被创建,只要不删除,其就会一直存在于zk中。
  • 持久顺序节点:一个父节点可以为其直接子节点维护一份顺序,用于记录子节点创建的先后顺序。在创建子节点时,会自动在指定的节点名称后添加数字后缀,作为该节点的完整名称。序号由10位数字组成,从0开始计数。
  • 临时节点:临时节点的生命周期与客户端的会话绑定在一起,会话消失则该节点也会消失。临时节点只能作为叶子节点,不能创建子节点。
  • 临时顺序节点:添加了创建序号的临时节点

节点状态

  • cZxidCreated Zxid,表示当前znode创建时的 事务ID
  • ctimeCreated Tiem,表示当前znode创建时间
  • mZxidModified Zxid,表示当前znode最后一次被修改时的 事务ID
  • mtimeModified Time,表示该znode最后一次被修改时间
  • pZxid:表示当前znode子节点列表最后一次被修改时的事物ID。(只能是子节点列表变更了才会引起pZxid的变更,子节点内容的修改不会影响pZxid
  • cversionChildren Version,表示子节点的版本号,该版本号用于充当乐观锁
  • dataVersion:表示当前znode数据的版本号,该版本号用于充当乐观锁
  • aclVersion:表示当前znode的权限ACL的版本号,该版本号用于充当乐观锁。
  • ephemeralOwner:若当前znode持久节点,则其值为0;若为临时节点,则其值为创建该节点的会话的SessionID。会话断开后会根据SessionID删除相关临时节点
  • dataLength:当前znode中存放的数据的长度
  • numChildren:当前znode所包含的子节点个数

会话

客户端和服务端之间的任何操作都与会话有关
Zookeeper客户端启动时,首先会与zk服务器建立一个TCP长连接,连接一旦建立,客户端会话的生命周期也就开始了。

会话状态

  • CONNECTING:连接中。Client要创建一个连接,首先会在本地 创建一个对象,用于表示其所连接上的Server。从zk对象被创建开始,会话状态就进入了CONNECTING,同时Client会从Server服务列表中通过轮询方式逐个尝试连接,直到连接成功。注意:在轮询前,其首先会将列表进行随机打散,然后再在打散的基础上进行轮询
  • CONNECTED:已连接。连接成功后,该连接的各种临时性数据会被初始化到zk对象
  • CLOSED:已关闭。连接关闭后,这个代表server的zk对象会被删除

会话连接超时管理—客户端维护

客户端所发起的服务端连接时间记录,是从客户端当前会话第一次发起服务端连接的时间开始计时。

会话空闲超时管理—服务端维护

服务端为每一个客户端的会话都记录上一次交互后空闲的时长,即从上一次交互结束后就开始会话空闲超时的时间计时。一旦空闲时长超时,服务端就会将该会话的SessionId从服务端清除。这也就是为什么客户端在空闲时需要向服务端发送心跳,就是为了维护这个长连接会话。服务器是通过空闲超时来判断会话是否发生中断的。
服务端对于会话空闲超时的管理,采用了一种特殊的方式—分桶策略

  • 分桶策略:将空闲超时时间相近的会话放到同一个桶中进行管理,以减少管理的复杂度。在检查超时的时候,只需要检查桶中剩下的会话即可,因为没有超时的会话已经被移出了桶,而桶中存在的会话就是超时的会话。zk对于会话空闲的超时管理并非精确的管理,即并非是一超时马上就执行相关的超时操作。
  • 分桶依据:从以下公式可知,一个桶的大小为ExpirationInterval时间。只要ExpirationTime落入到同一个桶中,系统就会对其中的会话超时进行统一管理。

    ExpirationTime = CurrentTime + SessionTimeout
    BucketTime = (ExpirationTime/ExpirationInterval + 1)*ExpirationInterval

会话连接事件

客户端和服务端的长连接失效后,客户端将进行重连。在重连的过程中客户端会产生三种会话连接事件

  • CONNECTION_LOSS: 连接丢失。由于网络抖动等原因造成客户端长时间无法收到服务端的心跳回复,客户端就会引发连接丢失事件。该事件会触发当前客户端重连服务端,直到连接成功或连接超时。
  • SESSION_MOVED: 会话转移。当发生连接丢失事件后,若客户端重新连接成功,但是此时连接成功的zk主机不是上一次连接的zk主机,此时服务端就会引发会话转移异常,而客户端就会引发会话转移事件,该事件会触发当前客户端使用第二次连接上的zk主机的地址与Server进行交互。
  • SESSION_EXPIRED: 会话失效。若服务端发现某客户端会话空闲时间超时,那么服务器就会将该客户端会话进行清除。对于客户端来说,其长时间没有收到服务端的心跳回复,就会引发连接丢失事件,然后重新连接,直到连接成功或超时。但在会话已经从服务端清除,而重新连接又未超时的一个短暂的事件缝隙中,客户端与服务端连接成功了,此时客户端就会引发会话失效事件。该事件会触发客户端取消该连接,并使客户端重新实例化zk对象,即使用新的SessionId进行重连。

ACL

ACL全称为Access Control List(访问控制列表),是一种细粒度的权限管理策略,可以针对任意用户与组进行细粒度的权限控制。zk利用ACL控制znode节点的访问权限,如znode数据读写、znode创建、znode删除、读取子节点列表、设置节点权限等。
Zookeeper的ACL分为三个维度:授权策略scheme授权对象id用户权限permission,子znode 不会 继承父znode的权限。

授权策略scheme

授权策略用于确定权限验证过程中使用的检测策略,在zk中常用的策略有

  • IP:根绝IP地址进行权限验证
  • digest:根据用户名和密码进行验证
  • world:对所有用户做任何验证
  • super:超级用户可以对任意znode进行任意操作。这种模式打开客户端的方式都与正常方式的不同,需要在打开客户端时添加一个系统属性

授权对象id

授权对象指的是权限赋予的用户。不同的授权策略具有不同类型的授权对象,下面是各个授权模式对应的授权对象id

  • ip: 授权对象是ip地址
  • digest:授权对象是用户名 + 密码
  • world:其授权对象只有一个,即anyone
  • Super:与digest相同,即授权对象为用户名 + 密码

权限permission

通过验证的用户可以对znode执行的操作,共有5种权限,而且zk支持自定义权限。

  • c:Create,允许授权对象在当前节点下创建子节点
  • d:Delete,允许授权对象删除当前节点。
  • r:Read,允许授权对象读取 当前节点的数据内容,及子节点列表
  • w:Write,允许授权对象修改 当前节点的数据内容,及子节点列表
  • a:Acl,允许授权对象对当前节点进行ACL相关的设置。

Watcher机制

zk通过Watcher机制实现了发布/订阅模式

watcher 工作原理

  1. ZKclient生成watcher对象,并存放到WatchManager
  2. ZKclientZKServer 注册 watcher
  3. ZKServer 发生 watcher 事件
  4. ZKServerZKClient 发送相应事件通知
  5. ZKClient根据通知从WatchManager中找到相应的watcher对象
  6. ZKClientwatcher对象执行相应回调

watcher

watcher 事件

客户端所处状态 事件类型(常量值) 触发条件 说明
SyncConnected None(-1) 客户端与服务器成功建立会话 此时客户端和服务器处于连接状态
NodeCreated(1) Watcher监听的对应数据节点被创建
NodeDeleted(2) Watcher监听的对应数据节点被删除
NodeDataChanged(3) Watcher监听的对应数据节点的数据内容发生变化
NodeChildrenChanged(4) Watcher监听的节点的子节点列表发生变化
Disconnected(0) None(-1) 客户端与zk服务器断开连接 此时客户端与服务器处于连接断开状态
Expired(-112) None(-1) 会话失效 此时客户端会话失效,通常会收到SessionExpiredException异常
AuthFailed None(-1) 使用错误的scheme进行权限检查 通常会收到AuthFailedException异常

watcher 特性

  • 一次性:一旦一个watcher被触发,zk就会将其从客户端WatcherManager删除服务端中也会删除watcherzkwatcher机制不适合监听变化非常频繁的场景。
  • 串行性:对于同一个节点相同事件类型的watcher回调方法的执行是串行的。
  • 轻量级:真正传递给Server的是一个简易版watcher。回调逻辑存放在客户端,没有在服务端。
文章作者:
文章链接: https://www.fundodoo.com/zh-CN/2020/04/01/54.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 醉探索戈壁
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论