文章摘要(AI生成)
Zookeeper维护持久节点和临时节点组成的空间,通过监听节点数据实现节点及其子节点的数据一致性。Zookeeper的数据存储结构与Unix文件系统相似,使用znode作为最小的数据单元,并可以保存数据和挂载子节点。节点类型包括持久节点、持久顺序节点、临时节点和临时顺序节点,它们具有不同的生命周期。会话是Zookeeper中重要的概念,客户端与服务端之间的交互操作都与会话相关。常见的会话状态有连接中、已连接和已关闭。
一句话可以概括为:zookeeper主要维护持久节点和临时节点组成的空间,通过对节点的数据的监听达到节点及其子节点最终的数据一致性
znode
zk数据存储结构与标准的Unix文件系统非常相似,都是在根节点下挂很多子节点。zk中没有引入传统文件系统中目录与文件的概念,而是使用了称为znode的数据节点概念。znode是zk中数据的最小单元,每个znode上都可以保存数据,同时还可以挂载子节点,形成一个树形化命名空间。
节点类型
每个znode根据节点类型的不同,具有不同的生命周期。
-
持久节点:节点被创建后会一直保存在zk中,直到将其删除。
- 持久顺序节点:一个父节点可以为它的第一级子节点维护一份顺序,用于记录每个子节点创建的先后顺序。
-
临时节点:临时节点的生命周期与客户端的会话绑定在一起,会话消失则该节点就会被自动清理。临时节点只能作叶子节点,即临时节点不能创建子节点。
- 临时顺序节点:添加了创建序号的临时节点。
会话
会话是zk中最重要的概念之一,客户端与服务端之间的任何交互操作都与会话相关。ZooKeeper客户端启动时,首先会与zk服务器建立一个TCP长连接。连接一旦建立,客户端会话的生命周期也就开始了。
会话状态
常见的会话状态有七种:
- CONNECTING:连接中。Client要创建一个连接,其首先会在本地创建一个zk对象,用于表示其所连接上的Server。
- CONNECTED:已连接。连接成功后,该连接的各种临时性数据会被初始化到zk对象中。
- CLOSED:已关闭。连接关闭后,这个代表Server的zk对象会被删除。
public enum States {
CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY,
CLOSED, AUTH_FAILED, NOT_CONNECTED;
public boolean isAlive() {
return this != CLOSED && this != AUTH_FAILED;
}
/**
* Returns whether we are connected to a server (which
* could possibly be read-only, if this client is allowed
* to go to read-only mode)
* */
public boolean isConnected() {
return this == CONNECTED || this == CONNECTEDREADONLY;
}
}
会话建立流程
1、解析节点列表,将解析到的节点连接地址使用Collections.shuffle()
对其进行随机排列
2、根据获取到的链接地址创建客户端连接,包括一个发送线程和一个watcher事件线程:
- 发送线程负责维护与zk节点的连接,如果连接关闭则发送关闭的watcher事件
- 事件线程负责处理watcher队列,根据watcher的连接状态和数据变更对其进行处理:
- 如果节点状态发生变更,则会根据更新后的状态对连接进行重连或关闭
- 如果节点数据发生变更,则会更新当前节点和其下的子节点数据内容
会话连接事件
- 连接丢失:因为网络抖动等原因导致客户端长时间收不到服务端的心跳回复,客户端就会导致连接丢失。连接丢失会引发客户端自动从 zk 地址列表中逐个尝试重新连接,直到重连成功,或 按照指定的重试策略终止。
- 会话转移:当发生连接丢失后,客户端又以原来的 sessionId 重新连接上了服务器。若重连上的服务器不是原来的服务器,那么客户端就需要更新本地 zk 对象中的相关信息,例如连接上的Server 的 IP 地址。这就是会话转移。
- 会话失效:若客户端连接丢失后,在会话超时范围内没有连接上服务器,则服务器会将该会话从服务器中删除。在服务端将某客户端的会话删除后,该客户端仍使用原来的 sessionId 又重新连接上了服务器。那么服务器会给客户端发送一个连接关闭响应,表示这个会话已经失效。 客户端在收到响应后会根据配置,要么关闭连接,要么重新发起新的会话 id 的连接。
会话超时管理
服务器为每一个客户端的会话都记录着上一次交互后空闲的时长,及从上一次交互结束开始会话空闲超时的时间点。一旦空闲时长超时,服务端就会将该会话的 SessionId 从服务端清除。
服务端对于会话空闲超时管理,采用了一种特殊的方式——分桶策略。
分桶策略是指,将空闲超时时间相近的会话放到同一个桶中来进行管理,以减少管理的复杂度。在检查超时时,只需要检查桶中剩下的会话即可,因为没有超时的会话已经被移出 了桶,而桶中存在的会话就是超时的会话。
分桶策略的计算公式为:
【过期时间】=【当前时间】+【会话超时时间】
【会话的过期桶】=(【过期时间】/【过期桶单位时间】+1)
【会话实际清除时间】=【过期桶】X【过期桶单位时间】
watcher事件
zk 的 watcher 机制具有非常重要的两个特性:
- 一次性:一旦一个 watcher 被触发,zk 就会将其从客户端的 WatcherManager 中删除, 服务端中也会删除该 watcher。zk 的 watcher 机制不适合监听变化非常频繁的场景。
- 轻量级:真正传递给 Server 的是一个简易版的 watcher。回调逻辑存放在客户端,没有在服务端。
一个watcher由节点路径,节点连接状态,节点变更事件组成。
其中节点连接状态包括:
public enum KeeperState {
/** 未使用,此状态从不由服务器生成 */
@Deprecated
Unknown (-1),
/** 客户端处于断开连接状态—它未连接到集群中的任何服务器。 */
Disconnected (0),
/** 未使用,此状态从不由服务生成 */
@Deprecated
NoSyncConnected (1),
/** 客户端处于连接状态-它连接到集成中的服务器(ZooKeeper客户端创建过程中主机连接参数中指定的服务器之一)。*/
SyncConnected (3),
/**
* 身份验证失败状态
*/
AuthFailed (4),
/**
* 客户端连接到只读服务器,即当前未连接到大多数服务器的服务器。
* 在接收到此状态之后,唯一允许的操作是读取操作。
* 此状态仅为只读客户端生成,因为不允许读/写客户端连接到I/o服务器。
*/
ConnectedReadOnly (5),
/**
* SaslAuthenticated:用于通知客户端他们已通过SASL身份验证,以便他们可以使用SASL授权权限执行Zookeeper操作。
*/
SaslAuthenticated(6),
/** 服务群集已使此会话过期。
* ZooKeeper客户端连接(会话)不再有效。如果要访问集群,必须创建一个新的客户端连接(实例化一个新ZooKeeper实例)。
*/
Expired (-112);
//......
}
节点变更事件包括:
None (-1), //当节点连接状态为Disconnected、Expired、AuthFailed,为此值
NodeCreated (1), //节点创建
NodeDeleted (2), //节点删除
NodeDataChanged (3), //节点数据变更
NodeChildrenChanged (4); //子节点变更
节点访问控制-ACL
ACL 全称为 Access Control List(访问控制列表),是一种细粒度的权限管理策略,可以针对任意用户与组进行细粒度的权限控制。zk 利用 ACL 控制 znode 节点的访问权限,如节点数据读写、节点创建、节点删除、读取子节点列表、设置节点权限等。
Zookeeper 的 ACL 分为三个维度:授权策略 scheme、授权对象 id、用户权
限 permission,子 znode 不会继承父 znode 的权限。
授权策略用于确定权限验证过程中使用的检验策略(简单来说就是,通过什么来验证权限,或一个用户要访问某个节点,系统如何验证其身份),在 zk 中最常用的有四种策略。
- 根据 IP 地址进行权限验证。
- 根据用户名与密码进行验证。
- 对所有用户不做任何验证。
- 超级用户可以对任意节点进行任意操作。
授权对象指的是权限赋予的用户。不同的授权策略具有不同类型的授权对象。
权限指的是通过验证的用户可以对 znode 执行的操作。共有五种权限:
- 创建权限:允许授权对象在当前节点下创建子节点。
- 删除权限:允许授权对象删除当前节点。
- 读权限:允许授权对象读取当前节点的数据内容,及子节点列表。
- 写权限:允许授权对象修改当前节点的数据内容,及子节点列表。
- 授权权限:允许授权对象对当前节点进行 ACL 相关的权限设置。
评论区