由于paxos实现起来有点难,并且存在活锁何个全序问题(无法保障两次最终提交的顺序),所以zookeeper选择了相对简单的ZAB协议
ZAB协议:是一种支持崩溃恢复的原子广播协议,基于fast paxos实现,ZooKeeper使用单一主进程Leader用于处理客户端所有事务请求,,即写请求。当服务器数据发生变更 好,集群采用ZAB原子广播协议,以事务提交proposal的形式广播到所有的副本进程,每一个事务分配 一个全局的递增的事务编号xid。 若客户端提交的请求为读请求时,则接受请求的节点直接根据自己保存的数据响应。若是写请求,且当 前节点不是leader,那么该节点就会将请求转发给leader,leader会以提案的方式广播此写请求,如果 超过半数的节点同意写请求,则该写请求就会提交。leader会通知所有的订阅者同步数据。
zookeeper的三种角色 :
为了避免
zk
的单点问题,
zk
采用集群方式保证
zk
高可用
- leader
leader
负责处理集群的写请求,并发起投票,只有超过半数的节点同意后才会提交该写请求
- follower
处理读请求,响应结果。转发写请求到
leader
,在选举
leader
过程中参与投票
observer
- observer可以理解为没有投票权的follower,主要职责是协助follower处理读请求。那么当整个zk
集群读请求负载很高时,为什么不增加
follower
节点呢?原因是增加
follower
节点会让
leader
在提
出写请求提案时,需要半数以上的
follower
投票节点同意,这样会增加
leader
和
follower
的通信通
信压力,降低写操作效率。
zookeeper两种模式
- 恢复模式
当服务启动或领导崩溃后,
zk
进入恢复状态,选举
leader
,
leader
选出后,将完成
leader
和其他机
器的数据同步,当大多数
server
完成和
leader
的同步后,恢复模式结束
- 广播模式
一旦
Leader
已经和多数的
Follower
进行了状态同步后,进入广播模式。进入广播模式后,如果有
新加入的服务器,会自动从
leader
中同步数据。
leader
在接收客户端请求后,会生成事务提案广播
给其他机器,有超过半数以上的
follower
同意该提议后,再提交事务。
注意在
ZAB
的事务的二阶段提交中,移除了事务中断的逻辑,
follower
要么
ack
,要么放弃,
leader
无需等待所有的
follower
的
ack
。
北京市昌平区建材城西路金燕龙办公楼一层 电话:400-618-9090
zxid
zxid
是
64
位长度的
Long
类型,其中高
32
位表示纪元
epoch
,低
32
位表示事务标识
xid
。即
zxid
由两部分
构成:
epoch
和
xid
每个
leader
都会具有不同的
epoch
值,表示一个纪元,每一个新的选举开启时都会生成一个新的
epoch
,新的
leader
产生,会更新所有的
zkServer
的
zxid
的
epoch
,
xid
是一个依次递增的事务编号。
- leader选举算法:
启动过程
- 每一个server发出一个投票给集群中其他节点
- 收到各个服务器的投票后,判断该投票有效性,比如是否是本轮投票,是否是 looking状态
- 处理投票,pk别人的投票和自己的投票 比较规则xid>myid “取大原则”
- 统计是否超过半数的接受相同的选票
- 确认leader,改变服务器状态
- 添加新server,leader已经选举出来,只能以follower身份加入集群中
崩溃恢复过程
- leader挂掉后,集群中其他follower会将状态从FOLLOWING变为LOOKING,重新进入leader选举
- 同上启动过程
消息广播算法:
一旦进入广播模式,集群中非
leader
节点接受到事务请求,首先会将事务请求转发给服务器,
leader服 务器为其生成对应的事务提案
proposal,
并发送给集群中其他节点,如果过半则事务提交;
- leader接受到消息后,消息通过全局唯一的64位自增事务id,zxid标识
- leader发送给follower的提案是有序的,leader会创建一个FIFO队列,将提案顺序写入队列中发送 给follower
- follower接受到提案后,会比较提案zxid和本地事务日志最大的zxid,若提案zxid比本地事务id 大,将提案记录到本地日志中,反馈ack给leader,否则拒绝
- leader接收到过半ack后,leader向所有的follower发送commit,通知每个follower执行本地事务