一. 系统模型
数据模型
1. ZNode是Zookeeper中数据的最小单元,每个ZNode上可以保存数据,也可以挂载子节点,因此构成了一个层次化的命名空间,称之为树;
2. Zookeeper中事务是指能改变Zookeeper服务器状态的操作,一般包括数据节点创建于删除,数据节点内容更新和客户端会话创建于失效等;
对于每一个事务请求,都会分配一个全局唯一的事务ID,用ZXID来表示,通常是一个64位数字,从ZXID中可以间接的识别这些请求的全局顺序;
节点特性
1. 节点类型可以分为持久节点PERSISTENT,临时节点EPHEMERAL,顺序节点SEQUENTIAL;
2. 持久节点是指被创建后会一直保存在服务器上,直到有删除操作主动清除这个节点;
3. 临时节点的声明周期和客户端的会话绑定在一起,临时节点不能创建子节点;
4. 顺序节点指创建节点时,Zookeeper会自动为节点名加上一个数字后缀,后缀上线是整型的最大值;
5. 每个数据节点也存储了本身的一些状态信息Stat,包括事务ID,版本信息和子节点个数等;
版本
1. 每个数据节点都具有三种类型的版本信息:version,cversion,aversion;
2. 版本表示数据变更操作的次数,即使变更没有引起数据内容的变化;
Watcher
1. 一次性:客户端和服务端注册的Watcher一旦被触发,就会被从相应的存储中移除,减轻服务端的压力,因此在使用上需要反复注册;
2. 客户端串行执行:客户端Watcher回调的过程是一个串行同步的过程,这为我们保证了顺序;
3. 轻量:Watcher通知非常简单,只会告诉客户端发生了时间,不会说明具体内容,需要客户端主动重新去获取数据;客户端向服务器注册Watcher的时候并不会把客户端真实的Watcher对象传递到服务端,仅仅只是在客户端请求中使用boolean类型属性进行了标记,服务端也仅仅保存了当前连接的ServerCnxn对象;
ACL
1. 权限模式:Scheme
IP:通过IP地址粒度来进行权限控制;
Digest:通过类似于“username:password”形式进行权限控制;
World:数据节点的访问权限对所有用户开放;
Super:超级用户可以对任意Zookeeper上的数据节点进行任何操作;
2. 权限:Permission
CREATE;DELETE;READ;WRITE;ADMIN;
二. 序列化与协议
1. 序列化:Jute
2. 协议:基于TCP/IP协议
三. 客户端
组成:
1. Zookeeper实例:客户端的入口;
2. ClientWatcherManager:客户端Watcher管理器;
3. HostProvider:客户端地址列表管理器;
4. ClientCnxn:客户端核心线程,内部又包含SendThread(IO线程,负责客户端和服务端直接的网络通信)和EventThread(事件线程,负责处理服务端事件);
客户端初始化过程:
1. 初始化Zookeeper对象:通过构造方法实例化一个对象,并创建一个客户端的Watcher管理器ClientWatcherManager;
2. 设置Watcher:通过构造函数的参数设置,并保存在ClientWatcherManager中;
3. 构造服务器地址列表管理器:构造方法中传入的服务器地址放在HostProvider中;
4. 创建并初始化客户端网络连接器:首先创建ClientCnxn来管理客户端与服务器的网络交互,同时初始化客户端两个核心队列outgoingQueue和pendingQueue,分别作为客户端的请求发送队列和服务端响应的等待队列,创建ClientCnxnSocket用来处理底层IO;
5. 初始化SendThread和EventThread:将ClientCnxnSocket分配给SendThread作为底层网络IO处理器,初始化EventThread的待处理事件队列waitingEvents,存放所有等待被客户端处理的事件;
会话创建阶段:
1. 启动SendThread和EventThread;
2. 获取一个服务器地址:HostProvider中的随机一个地址;
3. 创建TCP连接;
4. 构造ConnectRequest请求;
5. 发送请求;
响应处理阶段:
1. 接收服务端响应:ClientCnxnSocket接收到响应后首先判断客户端状态是否“已初始化”,如果未完成初始化直接交由readConnectResult处理;
2. 处理Response:ClientCnxnSocket对消息反序列化,得到ConnectResponse对象,获取sessionId;
3. 连接成功:通知SendThread线程,进一步设置会话参数,更新客户端状态;通知HostProvider当前连接的服务地址;
4. 生成事件:SendThread生成SyncConnected-None事件,代表客户端与服务器会话创建成功,传递给EventThread线程;
5. 查询Watcher:EventThread从ClinetWatcherManager中查询对应的Watcher,将SyncConnected-None事件放到EventThread的waitingEvents队列中;
6. 处理事件:EventThread不断从waitingEvents队列中取出待处理的Watcher对象,直接调用该对象的process接口方法,触发Watcher;
四. 会话
会话状态:CONNECTING,CONNECTED,CLOSE;
会话创建:
1. session:Zookeeper中的会话实体,代表了一个客户端会话;
基本属性:sessionID,全局唯一;TimeOut:会话超时时间;TickTime,下次会话超时时间点;isClosing,标记一个会话是否已经被关闭;
2. SessionTracker:会话管理器,负责会话的创建,管理和清理等工作;
五. 服务器启动
预启动:
1. 统一由QuorumPeerMain作为启动类;
2. 解析配置文件zoo.cfg;
3. 创建并启动历史文件清理器DatadirCleanupManager;
4. 判断是集群模式还是单机模式启动;
初始化:
1. 创建并初始化ServerCnxnFactory;
2. 创建数据管理器FileTxnSnapLog;
3. 创建QuorumPeer实例;代表了集群中的一台机器,不断检测当前服务器实例的运行状态,根据情况发起Leader选举;
4. 创建内存数据库ZKDatabase;管理所有会话记录以及DataTree和事务日志的存储;
5. 初始化QuorumPeer;
6. 恢复本地数据;
7. 启动ServerCnxnFactory主线程;
Leader选举:
1. 初始化Leader选举;
2. 注册JMX服务;
3. 检测当前服务器状态;
4. Leader选举;
六. Leader选举
选举流程:
1. 每个Server会发出一个投票,投票包含所推举的服务器的SID和ZXID;
2. 接收来自各个服务器的投票,包括检查是否是本轮投票,是否来自LOOKING状态的服务器;
3. 处理投票,优先检查ZXID,选出ZXID比较大的,如果相同就比较SID,SID大的服务器作为Leader;
4. 统计投票,大于或等于n/2+1;
5. 改变服务器状态,follower变为FOLLOWING,leader变为LEADING;
来源:https://www.cnblogs.com/bbbbs/p/12549302.html