分布式协议算法——ZAB协议

一、ZAB协议

ZAB协议全称就是ZooKeeper Atomic Broadcast protocol,是ZooKeeper用来实现一致性的算法,分成如下3个阶段:

  • fast leader election:快速选举阶段
  • recovery:恢复阶段
    • Discovery;
    • Synchrozation
  • broadcasting:广播阶段

先了解一些基本概念

  • electionEpoch:每执行一次leader选举,electionEpoch就会自增,用来标记leader选举的轮次
  • peerEpoch:每次leader选举完成之后,都会选举出一个新的peerEpoch,用来标记事务请求所属的轮次
  • zxid:事务请求的唯一标记,由leader服务器负责进行分配高32位是上述的peerEpoch,低32位是请求的计数,从0开始。
  • lastprocessZxid:最后一次commit的事务请求的zxid
  • LinkedList<Proposal> committedLog、long maxCommittedLog、long minCommittedLog:ZooKeeper会保存最近一段时间内执行的事务请求议案,个数限制默认为500个议案。committedLog就是用来保存议案的列表,maxCommittedLog表示最大议案的zxid,minCommittedLog表示committedLog中最小议案的zxid。
  • ConcurrentMap<Long, Proposal> outstandingProposals:Leader拥有的属性,每当提出一个议案,都会将该议案存放至outstandingProposals,一旦议案被过半认同了,就要提交该议案,则从outstandingProposals中删除该议案
  • ConcurrentLinkedQueue<Proposal> toBeApplied:Leader拥有的属性,每当准备提交一个议案,就会将该议案存放至该列表中,一旦议案应用到ZooKeeper的内存树中了,然后就可以将该议案从toBeApplied中删除。
  • state:当前服务器的状态
  • recvQueue:消息接收队列,用于存放那些从其他服务器接收到的消息。
  • queueSendMap:消息发送队列,用于保存那些待发送的消息,按照SID进行分组。
  • senderWorkerMap:发送器集合,每个SenderWorker消息发送器,都对应一台远程Zookeeper服务器,负责消息的发送,也按照SID进行分组。
  • lastMessageSent:最近发送过的消息,为每个SID保留最近发送过的一个消息。

在ZAB协议中,服务的的状态state有四种:

  • LOOKING:进入leader选举状态
  • FOLLOWING:leader选举结束,进入follower状态
  • LEADING:leader选举结束,进入leader状态
  • OBSERVING:处于观察者状态

二、协议算法的具体描述

1、Broadcasting过程

  • leader针对客户端的事务请求,创造出一个提案,zxid由leader决定,并将该提案的zxid,提案放到outstandingProposals Map中。
  • leader向所有的follower发送该提案,如果过半的follower回复OK的话,则leader认为可以提交该议案,则将该议案从outstandingProposals中删除,然后存放到toBeApplied中
  • leader对该议案进行提交,会向所有的follower发送提交该议案的命令,leader自己也开始执行提交过程,会将该请求的内容应用到ZooKeeper的内存树中,然后更新lastProcessedZxid为该请求的zxid,同时将该请求的议案存放到上述committedLog,同时更新maxCommittedLog和minCommittedLog
  • leader回复客户端,并将提案中ToBeApplied中删除

2、fast leader election过程

选举过程关注两个要点:刚启动时进行leader选举和选举玩leader后,刚启动的server怎么感知到leader

投票过程有两个比较重要的数据:

  • HashMap<Long, Vote> recvset:用于收集LOOKING、FOLLOWING、LEADING状态下的server的投票
  • HashMap<Long, Vote> outofelection:用于收集FOLLOWING、LEADING状态下的server的投票(说明leader选举已经完成)

具体的过程有:

1)服务器先自增electionEpoch,给自己投票:

从快照日志和事务日志中加载数据,得到本机器的内存树数据,以及lastProcessedZxid。投票内容为

  • proposedLeader:server自身的myid值,初始为本机器的id
  • proposedZxid:最大事务zxid,初始为本机器的lastProcessedZxid
  • proposedEpoch:peerEpoch值,由上述的lastProcessedZxid的高32得到

     然后向所有的服务器发送投票。

2)server接收到投票通知后,进行PK。

如果收到的通知中的electionEpoch比自己的大,则更新自己的electionEpoch为serverA的electionEpoch;如果、收到的通知中的electionEpoch比自己的小,则向serverA发送一个通知,将自己的投票以及electionEpoch发送给serverA,serverA收到后就会更新自己的electionEpoch。如果electionEpoch相同,PK的规则是proposedZxid,然后再是myId。

3)根据server的状态来判定leader

如果当前发来的投票的server的状态是LOOKING状态,则只需要判断本机器的投票是否在recvset中过半了,如果过半了则说明leader选举就算成功了,如果当前server的id等于上述过半投票的proposedLeader,则说明自己将成为了leader,否则自己将成为了follower。

如果当前发来的投票的server的状态是FOLLOWING、LEADING状态,则说明leader选举过程已经完成了,则发过来的投票就是leader的信息,这里就需要判断发过来的投票是否在recvset或者outofelection中过半了,同时还要检查leader是否给自己发送过投票信息,从投票信息中确认该leader是不是LEADING状态。

3、Recovery过程

一旦leader选举完成,就开始进入恢复阶段,就是follower要同步leader上的数据信息。

1)通信初始化

leader会创建一个ServerSocket,接收follower的连接,leader会为每一个连接会用一个LearnerHandler线程来进行服务;

2)重新为peerEpoch选举出一个新的peerEpoch

follower会向leader发送一个Leader.FOLLOWERINFO信息,包含自己的peerEpoch信息。leader的LearnerHandler会获取到上述peerEpoch信息,从中选出一个最大的peerEpoch,然后加1作为新的peerEpoch。然后leader的所有LearnerHandler会向各自的follower发送一个Leader.LEADERINFO信息,包含上述新的peerEpoch;follower会使用上述peerEpoch来更新自己的peerEpoch,同时将自己的lastProcessedZxid发给leader,leader的根据这个lastProcessedZxid和leader的lastProcessedZxid之间的差异进行同步。

3)已经处理的事务议案的同步

判断LearnerHandler中的lastProcessedZxid是否在minCommittedLog和maxCommittedLog之间

  • LearnerHandler中的lastProcessedZxid和leader的lastProcessedZxid一致,则说明已经保持同步了

  • 如果lastProcessedZxid在minCommittedLog和maxCommittedLog之间,从lastProcessedZxid开始到maxCommittedLog结束的这部分议案,重新发送给该LearnerHandler对应的follower,同时发送对应议案的commit命令。上述可能存在一个问题:即lastProcessedZxid虽然在他们之间,但是并没有找到lastProcessedZxid对应的议案,即这个zxid是leader所没有的,此时的策略就是完全按照leader来同步,删除该follower这一部分的事务日志,然后重新发送这一部分的议案,并提交这些议案

  • 如果lastProcessedZxid大于maxCommittedLog,则删除该follower大于部分的事务日志

  • 如果lastProcessedZxid小于minCommittedLog,则直接采用快照的方式来恢复

4)未处理的事务议案的同步

LearnerHandler还会从leader的toBeApplied数据中将大于该LearnerHandler中的lastProcessedZxid的议案进行发送和提交(toBeApplied是已经被确认为提交的)

LearnerHandler还会从leader的outstandingProposals中大于该LearnerHandler中的lastProcessedZxid的议案进行发送,但是不提交(outstandingProposals是还没被被确认为提交的)

5) 将LearnerHandler加入到正式follower列表中

6)LearnerHandler发送Leader.NEWLEADER以及Leader.UPTODATE命令。leader开始进入心跳检测过程,不断向follower发送心跳命令,不断检是否有过半机器进行了心跳回复,如果没有过半,则执行关闭操作,开始进入leader选举状态;LearnerHandler向对应的follower发送Leader.UPTODATE,follower接收到之后,开始和leader进入Broadcast处理过程。

三、事务持久化和恢复过程

事务持久化分为:broadcasting持久化和leader shutdown过程的持久化。

  • leader针对每次事务请求都会生成一个议案,然后向所有的follower发送该议案。follower收到提案后,将该议案记录到事务日志中,每当记满100000个(默认),则事务日志执行flush操作,同时开启一个新的文件来记录事务日志

    同时会执行内存树的快照,snapshot.[lastProcessedZxid]作为文件名创建一个新文件,快照内容保存到该文件中

  • 一旦leader过半的心跳检测失败,则执行shutdown方法,在该shutdown中会对事务日志进行flush操作

事务的恢复分为快照恢复和日志恢复。

  • 事务快照的恢复:会在事务快照文件目录下找到最近的100个快照文件,并排序,最新的在前;对上述快照文件依次进行恢复和验证,一旦验证成功则退出,否则利用下一个快照文件进行恢复。恢复完成更新最新的lastProcessedZxid;
  • 事务日志的恢复:从事务日志文件目录下找到zxid大于等于上述lastProcessedZxid的事务日志,然后对上述事务日志进行遍历,应用到ZooKeeper的内存树中,同时更新lastProcessedZxid,同时将上述事务日志存储到committedLog中,并更新maxCommittedLog、minCommittedLog

参考信息:https://my.oschina.net/pingpangkuangmo/blog/778927?spm=a2c4e.11153940.blogcont62901.11.12c62ee5vwzG6o

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值