基于zookeeper3.4.9
0.zk初始化
org.apache.zookeeper.server.quorum.QuorumPeerMain#initializeAndRun()方法,初始化操作,通信管理和参数加载等。
1.zookeeper选举
leader状态确认:
选举出来的leader和followers需要经过,通信,确认有半数的followers通信ack之后,才确认了各自的状态。
QuorumPeer.run(){}方法,进行状态判断,如果为LOOKING,则进行选举算法;
选举算法(红框中为选举算法的具体实现)通过选举,得到leader节点==>currentVote,以及自己节点的选举状态;
具体投票如下:
1.每个节点启动时,拿到自己的zxid,从历史数据中获取,默认值为0;实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
logicalclock为选举轮数,在同一轮的选票,才有效;
peerEpoch:每次leader选举完成之后,都会选举出一个新的peerEpoch,用来标记事务请求所属的轮次为节点历史选举为leader轮数,每参与一轮选举,leader的peerEpoch,在所有节点中取最大的peerEpoch+1;
recvset:选举过程中,选票箱的概念,里面存放着所有选举者的选票
outofelection:接受到的leader节点的选票;如果由于网络故障,当前leader挂断,新的选举产生,leader节点又恢复时,就会出现leader的选票了;
选举开始,选举时钟+1;
选举开始时,初始化选举基本参数获取其他节点广播的选票;
获取其他节点广播的选票;选票解读:
选票解读具体步骤:
1.不在一个选举轮次,比当前节点的轮次大,清空当前节点的选票箱,同意n节点的票,广播给其他节点。
2.比当前节点轮次小,忽略。
3.totalOrderPredicate(),选票对比:
选票对比1) peerEpoch对比,谁大选谁;
2)peerEpoch相等,谁的zxid大,或者zxid相等但节点id大,选谁。
3)如果n节点的选票更优,则更新自己的选票。
4.将收到的选票放入选票箱。
票数过半以后:
票数过半以后,确认节点状态,退出选举算法,做后续确认工作1.确认选票箱中的选票,有节点票数过半,返回当前选票。(FastLeaderElection.termPredicate())
确定票数过半逻辑2.recvqueue 中持续在获取其他节点的选票,设置的200ms超时,以防网络延时。在这个过程中,如果网络延时,节点B已经当选了Leader返回出来了,但是A在这个时候还没有退出,又接受到了D,E节点的选票,会继续选举,结果又选出了E节点为Leader,这时候,就出现了双leader的情况,下面就需要进行确认机制,排除其他leader,剩下一个leader节点。
Synchronization确认leader节点
自己的状态如果为leader,则调用leader.lead(),方法,做选举成功以后的事情
leader的主要逻辑开启阻塞,等待follower的确认。
开启learnnerHandler,(LeaderHandler是follower和observer的主要通信逻辑类),ss监听开启,不断接收信息,有一个信息出来,就执行一个LearnHandler,
开启与follower的长连接与follower节点通信,确认,然后followerCounter+1;
Leader的确认消息Leader.lead()方法,会等待follower的确认,
等待确认,阻塞方法 等待确认具体路基如果不是真正的leader节点,弹出异常,退出leader.lead()方法,当前节点退出,重新进入选举流程。
Follower.follower()方法,主要给leader发送消息确认,然后进入接受消息的状态。
源码下次再说吧。
网友评论