接上文 手把手带你撸zookeeper源码-zookeeper启动(四)leader选举投票发送以及响应
本篇文章主要来看看当每个zk接收到其他服务器发送过来的投票之后,接下来会怎么处理
//投票归档
recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));
if (termPredicate(recvset,
new Vote(proposedLeader, proposedZxid,
logicalclock.get(), proposedEpoch))) {
// Verify if there is any change in the proposed leader
while((n = recvqueue.poll(finalizeWait,
TimeUnit.MILLISECONDS)) != null){
if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
proposedLeader, proposedZxid, proposedEpoch)){
recvqueue.put(n);
break;
}
}
if (n == null) {
self.setPeerState((proposedLeader == self.getId()) ?
ServerState.LEADING: learningState());
Vote endVote = new Vote(proposedLeader,
proposedZxid,
logicalclock.get(),
proposedEpoch);
leaveInstance(endVote);
return endVote;
}
}
recvset是一个HashMap集合,key为zk的sid, value: 就是投票对象Vote,里面包含了投票的数据,比如投票给谁作为leader,zxid等
再来看看termPredicate方法
protected boolean termPredicate(
HashMap<Long, Vote> votes,
Vote vote) {
HashSet<Long> set = new HashSet<Long>();
for (Map.Entry<Long,Vote> entry : votes.entrySet()) {
if (vote.equals(entry.getValue())){
set.add(entry.getKey());
}
}
return self.getQuorumVerifier().containsQuorum(set);
}
打个比方来说明更简单一些: 当前服务器是zk2, 然后 zk1向zk2发送投票数据,投票给zk3,此时这段的代码的意思就是遍历zk2服务器保存的所有投票数据,即votes。vote是zk1向zk2发送过来的投票数据,从votes集合中取出所有投了zk3的投票,把他们放入到set集合中
接下来看看containsQuorum()方法代码,进入的是QuorumMaj
public boolean containsQuorum(Set<Long> set){
return (set.size() > half);
}
很简单的代码,就是判断给zk3投的票数是不是超过了zk集群所有服务器总数的一半,如果是,则会把zk3作为leader,如果没有超过一半,则会接着继续投票
接下来就是判断是否还有其他zk发送过来的数据,如果有则继续处理
while((n = recvqueue.poll(finalizeWait,
TimeUnit.MILLISECONDS)) != null){
if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
proposedLeader, proposedZxid, proposedEpoch)){
recvqueue.put(n);
break;
}
}
如果没有了,则会走下面的代码
if (n == null) {
self.setPeerState((proposedLeader == self.getId()) ?
ServerState.LEADING: learningState());
Vote endVote = new Vote(proposedLeader,
proposedZxid,
logicalclock.get(),
proposedEpoch);
leaveInstance(endVote);
return endVote;
}
首先判断当前投递的leader的sid是否和本服务器myid一样,如果一样,则设置peerState为LEADING,作为leader,否则就设置状态为FOLLOWING或者OBSERVER,最后清空recvqueue, 返回有关leader的投票对象数据,leader整个选举结束
这篇文章就先写这么多,每次zk接受到其他的投票数据都会保存一下投票结果,然后对投票结果进行统计是否有sid的票数超过了集群总服务器数的一半,如果超过就可以确定leader,同时确定follower和observer
下篇文章来分析一下,当zk知道自己的角色之后,怎样按照自己的角色去做响应的事情