目录
七、Zookeeper技术内幕
7.1系统模型
7.1.1数据模型
7.1.2 节点类型
7.1.3 Znode的版本信息——保证分布式数据操作的原子性
7.1.4 Watcher——数据变更通知
7.1.5 ACL访问控制
7.2序列化协议
7.3 客户端
7.4 会话
7.4.1 会话状态转换
7.4.2 会话创建
七、Zookeeper技术内幕
ZK最重要的一点就是利用自己的数据模型实现分布式系统的一致性
7.1系统模型
7.1.1数据模型
Znode数据节点是最小单元,由Znode构成了树。
对于每一个事务请求,Zookeeper都会为其分配一个全局的事务ID,用ZXID来表示,每个ZXID对应一次更新操作,ZXID用来保证全局顺序操作
7.1.2 节点类型
持久节点(PERSISITENT),临时节点(EPHEMERAL)和顺序节点(SEQUENTIAL),具体创建过程中,会形成
持久节点,持久顺序节点,临时节点,临时顺序节点四类,其中临时节点只能作为叶子节点,且与会话绑定,而非TCP连接
7.1.3 Znode的版本信息——保证分布式数据操作的原子性
Znode的版本信息用来保证分布式数据的原子性操作,每个数据节点有三个版本信息
version表示当前节点自从创建之后被更新的次数,即使数据一样,只要版本发生变化,version就会改变,例如当一个Znode被创建后,其version为0,同样,这样的改变也会存在所谓ABA问题,所以这里的版本并不是指Znode的本身的内容是否变化,而是是否有用户对节点内容进行变更。
乐观锁控制事务分成如下三个阶段:数据读取,写入校验,和数据写入
Znode在进行setDataRequest时会进行版本比较,客户端可以使用CAS,也可以不使用CAS,如果使用但版本不一致,会抛出BadVersionException异常
7.1.4 Watcher——数据变更通知
客户端向服务端注册Watcher监听,当服务端一些指定的事件触发了Watcher,那么就会向指定客户端发送一个事件通知来实现分布式通知功能
Client向zookeeper注册Watcher时,会将Watcher信息存储在WatchManager中,当服务端出发Watcher事件之后,会向客户端发送通知,客户端线程从WatchManager中取出Watcher执行相应的回调逻辑。
Watcher接口内定义了两个枚举:KeeperState和EventType和一个方法process(WatchedEvent event)
本质上,还是在服务端维护了一个Map
总结Watcher特性:
一次性:一旦一个Watcher被触发,就会从Set
轻量:WatchedEvent是整个Zookeeper做Watcher的最小通知单元,且只包含三个成员变量,也就是说process回调只会告诉客户端发生了事件,而不会说明事件的具体内容,对于变更前后的数据都需要客户端自己去获取。从而做到轻量级的通知机制。
7.1.5 ACL访问控制
UGO(user,group,others)转为ACL(Scheme:id:permission)
7.2序列化协议
Zk采用jute序列化组件
7.3 客户端
核心部件:
Zookeeper实例:ClientWatcherManager客户端WatcherManager
HostProvider:服务器地址管理器
ClientCnxn:客户端核心线程,其中又包含SendThread(用于建立TCP通信)和EventThread(事件处理线程),ZK客户端创建一次会话的过程:
7.4 会话
7.4.1 会话状态转换
图片来源:[ZooKeeper]ZooKeeper的会话状态_zjysource的专栏-CSDN博客_zookeeper会话状态
会话状态CONNECTING,CONNECTED,RECONNECTING,RECONNECTED,CLOSE。7.4.2 会话创建
(1)Session客户端会话实体
interface Session {
// 用sessionId唯一标识一个会话
long getSessionId();
// 超时时间
int getTimeout();
// 是否已经关闭
boolean isClosing();
}
sessionId生成规则,左移24位是为了把二进制日期前的0都移除,之后无符号右移8位,把高8位给id腾出位置,之后把id按位与在64位时间的高8位,最终得一个根据时间唯一确定的sessionId。(每次一有时间生成id我就想到时钟回拨。。)
public static long initializeNextSessionId(long id) {
long nextSid;
nextSid = (Time.currentElapsedTime() << 24) >>> 8;
nextSid = nextSid | (id << 56);
if (nextSid == EphemeralType.CONTAINER_EPHEMERAL_OWNER) {
++nextSid; // this is an unlikely edge case, but check it just in case
}
return nextSid;
}
最后,为了管理session,ZK提供了SessionTracker接口进行管理。
// sessionId和session的映射 protected final ConcurrentHashMapsessionsById = new ConcurrentHashMap (); // session和session超时时间的映射 protected final ConcurrentMap sessionsWithTimeout;
7.4.3 会话管理
ZK的会话管理主要是由SessionTracker负责,采用“分桶策略”,



