ZAB选主机制
what:
ZAB是zookeeper中支持崩溃恢复的一致性协议。基于该协议,zookeeper构建主从模式的架构,从而支持集群中各副本的数据一致性。
工作方式:所有更新操作,都会发往主结点(Leader),然后主结点(Leader)将日志写入本地日志,再将日志复制到从结点(follower)。如果Leader故障,就会从follower群里再选一个主。(和raft类似)
election epoch:分布式系统中,无法使用精准的时钟来维护事件的先后。Lampert提出的Logical Clock就成为了界定事件顺序的最主要方式。分布式系统中以消息标记事件,每个消息都会加上一个逻辑的时间戳(即Logical Clock)。在ZAB协议中,该Logical Clock就是zxid(全局唯一)。zxid是64位的数值,由Leader来生成,其高32位即为epoch,低32位是该epoch中的自增id;新选Leader的epoch会比老的大(一版是加1)。类比历史朝代,epoch就是朝代,自增id就是该朝代的记事了。
结点的三状态:LOOKING/FOLLOWING/LEADING
LOOKING: 节点正处于选主状态,不对外提供服务,直至选主结束;
FOLLOWING:作为系统的从节点,接受Leader主节点的更新并写入本地日志;
LEADING:为系统主节点,接受client客户端更新,写入本地日志并复制到从节点;
when(选主时机):
结点启动:
每个结点启动时都是LOOKING状态,处于观望态,然后进行选主;
Leader结点异常:
Leader结点会定期的向followers发送心跳信息(即ping),如果一个follower未收到心跳,那么该follower的状态就会由FOLLOWING变为LOOKING,然后进入选主阶段;
多数Follower结点异常:
Leader结点也会检查Followers结点的状态,如果多数Follower结点不再响应Leader结点(可能Leader和Follower结点之间的网络发生了分区)。此时,该Leader将不再是合法的Leader了,需要重新选主;
how(如何选主):
选主参与者:
发起选主者; 集群其他参与者(为发起者投票);
选主依据:
election epoch(A) > election epoch (B);
zxid(A) > zxid(B);
sid(A) > sid(B);
选主流程:
1、发起者A初始化自身的zxid和epoch:updateProposal();
2、向其他所有节点发送选主通知:sendNotifications();
3、A等待其他节点的回复:recvqueue.poll();
4、如果B节点(参与者)的回复不为空,且B是一个有效节点,判断B此时的运行状态是LOOKING(也在发起选主)还是LEADING/FOLLOWING(正常请求处理过程);
B结点LOOKING状态:
1、A发起一次选主请求,并将请求广播至B、C节点,而此时B、C也恰好处于LOOKING状态:
2、B、C节点处理A的选主消息,其中,B接受A的提议,C拒绝A的提:
伴随着A的选主消息,B和C此时都获得了A节点选主的结果(A投票给自己,记录为<A, A>),并记录该信息,作为后续判断大家是否达成一致的标准。
3、B将处理结果通知A、C:
a、B更新了自己的投票,从投票给自己变成投票给A,因此根据协议的定义,需要将该消息扩散出去。而C由于拒绝了A的提议,因此,无需扩散消息;
b、B将消息扩散给A和C的同时,A和C也就了解了B的投票信息,可以更新本地的投票信息表;
4、C同时也发起选主:
5、A、B分别处理C的选主请求:
A和B判断得出C是最合适的Leader,因此A和B都更新自己的候选Leader为C;同时由于C的消息,A和B都更新自身维护的投票信息,增加C的投票信息。
6、A、B将更新后的信息扩散到其他节点:
7、选主结束:所有的节点都已经达成了一致:每个节点都同意节点C作为新的Leader。
B结点是FOLLOWING/LEADING状态:
可能情况:
1、结点A(Follower,发起选主者)与Leader出现网络问题而触发一次选主,但是其他Follower与Leader正常;
2、结点A加入集群;
方案1:Logical Clock相同,如果Sender(发起者)宣称自己是Leader,那么判断是不是半数以上的服务器都选举它,如果是设置角色并退出选举。
方案1具体情况:A、B同时发起选主,此时他们的election epoch可能相同。如果B率先完成了选主过程(B可能变成了Leader,也有可能B选择了其他节点为Leader),但是A还在选主过程中。那么B就将自己的选主结果和自己的状态(LEADING/FOLLOWING)连同自己的election epoch回复给A。此时,A就是出现了1的情况,如下图:10表示选主的Logical Clock。
方案2:LogicalClock不同时,说明在另一个选举过程中已经有了选举结果。
方案2具体情况:
a、可能是由于原集群中有一个新的服务器上线/重新启动,但是原来的已有集群的机器已经选主成功,因此,别无他法,只有加入原来的集群成为Follower。
b、可能是因为某个节点出现了网络隔离导致其触发一次新的选主,然后系统中其他节点状态依然正常。发起选主的节点要递增其logical clock,则大于(网络隔离的老结点),
如果对方节点处于FOLLOWING/LEADING状态,除检查是否过半外,同时还要检查leader是否给自己发送过投票信息,从投票信息中确认该leader是不是LEADING状态。
该方案原因:此时leader和follower都需要各自检测是否进入leader选举过程。leader检测到未过半的server的ping回复,则leader会进入LOOKING状态;follower有自己的检测,感知这一事件,还需要一定时间;在此期间,如果其他server加入到该集群,可能会收到其他follower的过半的对之前leader的投票,但是此时该leader已经不处于LEADING状态了,所以需要这么一个检查来排除这种情况。