Zk 架构设计
角色
leader:
- 事务请求的调度和处理,保证集群事务处理的顺序性
- 集群内部各服务器的调度者
leader内部使用责任链处理客户端的请求:
- PrepRequestProcessor 请求预处理器,识别是否是事务请求, 对事务请求创建请求事务头,事务体, 会话检查,ACL检查和版本检查
- ProposalRequestProcessor 事务投票处理器,事务处理流程的发起者, 对于非事务请求, 将请求转发到CommitProcessor处理器, 对于事务请求: 1.将请求转发到CommitProcessor处理器;2.根据请求类型创建对应的Proposal提议, 发送给所有的Follower服务器发起集群内的事务投票;3.僵尸舞请求交付给SyncRequestProcessor进行事务日志记录
- SyncRequestProcessor 事务日志记录处理器, 触发Zk进行数据快照
- AckRequestProcessor 在完成事务日志记录后,向Proposal的投票收集器发送ACK反馈,通知收集器当前服务完成事务记录
- CommitProcessor 事务提交处理器,非事务请求,直接交付给下级处理器处理,集群请求等待集群内针对Proposal投票直到Proposal可被提交, 服务器很好的控制对事务处理的顺序处理
- ToBeAppliedProcessor 处理器有一个toBeApplied队列,用来存储已被CommitProcessor处理过的可被提交的Proposal。将请求交付给FinalRequestProcessor处理器处理,处理后,从toBeApplied队列中删除
- FinalRequestProcessor 用来进行客户端请求返回之前的操作,包括创建客户端请求的响应, 针对事务请求, 负责将事务应用到内存数据库中。
follower:
- 处理非事务请求, 转发事务请求给leader,
- 参与事务请求Proposal的投票
- 参与leader选举的投票
- FollowerRequestProcessor识别是否是事务请求, 如果是,将请求转发给Leader
- SendAckRequestProcessor 事务日志记录,完成后,向Leader发送ACK请求
observer:
- 不参与任何投票
- 只提供非事务请求服务,不影响集群事务处理能力的前提下,提升集群非事务处理的能力。
- 和Follower请求处理链很相近, 不同的是Observer服务器在初始化的时候会讲SyncRequestProcessor处理器组装上去,但实际运行过程中,Leader不会讲事务请求发送给Observer服务器
##observer 配置
peerType=observer
server.4=192.168.1.1:2888:3888
顺序一致性
顺序一致性是针对单个操作,单个数据对象,一个数据被更新后能够立马被后续的读操作读到, zk的顺序一致性是缩水版的。zk不保证在不同实例中具有相同的zk数据视图, 如果两个客户端尧都区相同的值, 在读取前执行zookeeper#sync方法.
zk基于zxid和阻塞队列的方式实现请求的顺序一致性, 如果一个client连接到还没有数据同步的follower上,client记录自己已经读取到的最大zxid和server对比,如果client大,连接失败
zk保证了"Single System Image", 表达的是client只要连接过一次zk, 就不会有历史倒退
ZAB 协议
原子广播
- leader接收到消息请求后, 将消息赋予一个全局唯一的64位自增ID,zxid, 通过zxid的大小比较可以实现因果有序
- leader为每个follower准备了FIFO队列, 将带有zxid的消息作为一个提案分发给所有follower
- 当follower接收到proposal, 先将proposal写到磁盘,写入成功后向leader回复ack
- 当leader接收到合法数量的ack后,leader向follower发送commit命令, 同时在本地执行该消息
- 当follower收到消息的commit命令后,会提交该消息
崩溃恢复
崩溃恢复状态下zab协议需要做两件事: 选举出新的leader和数据同步
已经被处理的消息不能丢弃
在各个follower节点在收到COMMIT命令前leader挂了, ZAB协议需要保证事务最终在所有的服务器上都能提交成功
被丢弃的消息不能再次出现
leader接收到消息请求生成proposal后挂了, 其他follower没有接收到此proposal, 此proposal应该被剔除
zxid
zxid是64位的数字, 高32位是epoch,用来标识leader关系是否改变, 低32位用于递增计数
事务日志
zk数据持久化在磁盘, 默认/tmp/zookeeper下,存放事务日志和快照日志
# 内存数据库快照
dataDir=/zk/data
# 事务日志
dataLogDir=/zk/data/log
文件命名是log.zxid, zxid标识当前日志文件开始记录的第一条数据的zxid.
# 事务日志查看命令
java -cp :/data/program/apache-zookeeper-3.6.1-bin/lib/slf4j-api-1.7.25.jar:/data/program/apache-zookeeper-3.6.1-bin/lib/zookeeper-jute-3.6.1.jar:/data/program/apache-zookeeper-3.6.1-bin/lib/zookeeper-3.6.1.jar org.apache.zookeeper.server.LogFormatter log.1
# 快照查看命令
java -cp :/data/program/apache-zookeeper-3.6.1-bin/lib/slf4j-api-1.7.25.jar:/data/program/apache-zookeeper-3.6.1-bin/lib/zookeeper-jute-3.6.1.jar:/data/program/apache-zookeeper-3.6.1-bin/lib/zookeeper-3.6.1.jar:/data/program/apache-zookeeper-3.6.1-bin/lib/snappy-java-1.1.7.jar org.apache.zookeeper.server.SnapshotFormatter snapshot.1
leader选举
选举状态:
LOOKING: 竞选状态 FOLLOWING: 随从状态,同步leader状态, 参与投票 OBSERVING: 观察状态, 同步leader状态, 不参与投票 LEADING: 领导者状态
- 每个Server发出一个投票, 初次,每个Server都投向自己
- 接受来自各服务器的投票, 检验epoch, 检验LOOKING状态
- 处理投票,比较epoch, 再比较ZXID, 比较myid
- 统计投票
- 改变服务器状态