zookeeper中有很多逻辑是等到超过一半选票才能继续的场景。来看看怎么实现的吧
Leader.getEpochToPropose
在选出来主之后,会进入到这个分支
QuorumPeer#
case LEADING: LOG.info("LEADING"); try { setLeader(makeLeader(logFactory)); leader.lead(); setLeader(null); } catch (Exception e) { LOG.warn("Unexpected exception", e); } finally { if (leader != null) { leader.shutdown("Forcing shutdown"); setLeader(null); } updateServerState(); } break; }
同时,follower也会进入自己的follow分支,简单说下逻辑,就是和leader建立通信,然后发送消息,表示要和leader进行数据同步。
消息类型为 Leader.FOLLOWERINFO
这里忽略leader的网络通信部分逻辑。直接看获取epoch的逻辑。
protected final Set<Long> connectingFollowers = new HashSet<Long>();
public long getEpochToPropose(long sid, long lastAcceptedEpoch) throws InterruptedException, IOException { synchronized (connectingFollowers) { if (!waitingForNewEpoch) { return epoch; } if (lastAcceptedEpoch >= epoch) {//找followe传过来的epoch最大值然后 +1 epoch = lastAcceptedEpoch + 1; } if (isParticipant(sid)) { connectingFollowers.add(sid); } QuorumVerifier verifier = self.getQuorumVerifier(); if (connectingFollowers.contains(self.getId()) && verifier.containsQuorum(connectingFollowers)) {//超过一半了 waitingForNewEpoch = false;//这里改为false 下面的while就会跳出了 self.setAcceptedEpoch(epoch); connectingFollowers.notifyAll();//唤醒阻塞 } else { long start = Time.currentElapsedTime(); if (sid == self.getId()) { timeStartWaitForEpoch = start; } long cur = start; long end = start + self.getInitLimit() * self.getTickTime(); while (waitingForNewEpoch && cur < end && !quitWaitForEpoch) { connectingFollowers.wait(end - cur); cur = Time.currentElapsedTime(); } if (waitingForNewEpoch) { throw new InterruptedException("Timeout while waiting for epoch from quorum"); } } return epoch; } }
QuorumVerifier 可以简单地理解就是比较是否大于集群服务器数量的一半的工具类
向connectionFollowers中添加记录的逻辑在LearnerHandler
不断地收到follower发过来的请求,慢慢的就满足了半数条件了
@Override public void run() { try { ......long newEpoch = learnerMaster.getEpochToPropose(this.getSid(), lastAcceptedEpoch);//不断向connectionFollowers中增加元素