深入了解Zookeeper

蓝咒 提交于 2020-03-23 03:56:11

一. 系统模型

数据模型

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;

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!