《从paxos到zookeeper分布式一致性原理与实践》笔记
1 数据模型
- znode节点,类似于文件目录结构
- 64位事务id,高32位leader id,低32位事务id。 创建/删除节点,更改节点数据
-
节点数据+节点状态
- 版本
节点更改次数,比如version表示当前节点创建后数据变更次数
支持客户端请求修改数据时使用基于version的乐观锁 -
watcher,数据变更通知
- NodeDataChanged事件包括数据内容变更和数据版本变更
- 事件触发后,通知给zk客户端。zk客户端调用process接口处理事件
public interface Watcher {
void process(WatchedEvent var1);
}
- WatchedEvent属性包含通知状态,事件类型,节点路径
public class WatchedEvent {
private final KeeperState keeperState;
private final EventType eventType;
private String path;
}
- WatcherEvent类是WatchedEvent的一个序列化的包装类,用于客户端和服务端之间通信
- 处理流程:客户端注册watcher -> 服务端存储watcher,事件操作->服务端触发对应事件watcher处理 -> 发送watcherevent给客户端 -> 客户端回调watcher。
- watcher一次性,回调后需要重新注册。
串行回调执行,避免回调函数中处理事件过长
仅通知有变更,实际数据需要重新获取 - 节点权限管理,创建,删除,读,写,管理
2 序列化
3 客户端
- Zookeeper 入口对象
ZKWatchManager watcher管理器
HostProvider地址列表管理器
ClientCnxn 客户端核心线程,包含两个线程
sendThread,i/o线程,负责客户端和服务端通信
EventThread,事件线程,处理服务端事件 -
初始化流程
1 初始化zookeepr对象,创建watcher管理器ClientWatchManager
2 设置会话默认Watcher
3 构造服务器地址列表HostProvider
4 构建并初始化客户端网络连接器ClientCnxn
outgoingQueue 客户端请求队列,pendinQueue服务响应队列
客户端io处理器ClientCnxnSocket
5 初始化sendThread和eventThread,
6 启动sendThread和eventThread线程
7 sendThread根据服务器地址建立tcp连接
8 构造ConnectRequest请求,封装成Packet对象,放入outgoingQueue队列中
9 tcp socket从队列获取packet对象,发送
10 接收请求响应,readConnectResult函数处理
11 解析ConnectResponse,获取zookeeper的会话id,sessionId
12 生成事件SyncedConnect,发送给EventThread
13 EventThread查询事件watcher,放入waitingEvents队列中
14 EventThread从队列中获取watcher,调用processor()接口函数 -
请求发送和响应处理图
4 会话
-
状态流转
- 会话结构
public static class SessionImpl implements Session {
final long sessionId;//全局唯一会话id
final int timeout;//超时时间,服务端根据客户端超时时间协商
long tickTime;//下次超时时间
boolean isClosing;//会话是否被关闭
}
4.1 SessionTracker服务端会话管理器
- SessionTracker分桶策略管理会话,根据会话下次超时时间分桶
- 在服务端接收到客户端心跳或操作请求报文,进行会话激活,计算下次超时时间,迁移会话到匹配的桶中
- 中超时检测线程,检查最近一个桶里的会话,可能是超时会话
- 会话清理
超时后先标记isClosing
获取会话的临时节点,考虑执行中的节点删除和节点创建
创建节点删除事务请求
删除临时节点
删除会话
关闭会话对应的server socket - 连接断开,会话超时,会话迁移
5 服务器启动
初始化FileTxnSnapLog,上层服务器和底层数据存储之间的接口,包括对事物日志文件和快照数据文件的访问。
初始化ServerCnxnFactory,netty服务端,接收数据
基于事务日志文件和快照数据文件恢复数据
初始化会话管理器,sessionTracker
-
初始化请求处理链PreRequestProcessor->SyncRequestProcessor->FinalRqeustProcessor ...
注册jmx服务
5.1 集群方式额外多leader选举过程
- 基于服务器id+zxid+当前服务器epoch 生成选票
zxid最大的当选leader, zxid相同则服务器id最大的当选leader - 选举完成后,确认leader角色,和following角色
following和leader建立连接,同步数据,启动服务。
6 leader选举
6.1 启动阶段选举
- 服务器投票给自己,构建选票(myid+zxid)
- 接收其他服务器选票
- 处理选票,zxid最大的当选,zxid相同的myid最大的当选
有变更的重新向其他服务器发送选票 - 统计投票,过半数的选为leader。
- 更新各服务器角色,然后following和leader建立连接,同步数据
6.2 服务运行期间选举
leader网络断开,奔溃重启
所有服务器状态变为looking,开始选举,发送选票
统计选票,选出leader,更改状态,同步数据
-
选票格式
6.3 QuorumCnxManager
- 网络I/O处理器
- 消息接收队列,接收其他服务器消息
- 消息发送队列,每个服务器一个发送队列
7 服务器角色
leader,follower,observer
8 请求处理
-
会话创建请求
-
setData,
-
getData,
事务请求转发
保证事务顺序执行,都由leader处理。事务请求转发给leader
9 数据存储
内存数据,
- 事务日志,
64m统一
名称后缀为第一个事务日志id - 数据快照,格式和事务日志类似
- 数据同步
差异化同步
全量同步
先回滚后同步
仅回滚