系列文章目录
【zookeeper核心源码解析】第一课:zk启动类核心流程序列图
【zookeeper核心源码解析】第二课:俯瞰QuorumPeer启动核心流程,实现选举关键流程
【zookeeper核心源码解析】第三课:leader与follower何时开始同步,如何同步数据
【zookeeper核心源码解析】第四课:客户端与服务端读写的io核心流程
【zookeeper核心源码解析】第三课:leader与follower何时开始同步,如何同步数据
1. leader准备好同步线程
leader.lead() 方法内部初始化LearnerCnxAcceptor后台线程,该线程用于与flollower同步数据:
cnxAcceptor = new LearnerCnxAcceptor();
cnxAcceptor.start();
2. follower开始同步
follower选举成功后,就开始同步,在上一节中,得知follower选举成功后执行follower.followLeader() 该方法会同步
源码如下:
/**
* the main method called by the follower to follow the leader
*
* @throws InterruptedException
*/
void followLeader() throws InterruptedException {
self.end_fle = System.currentTimeMillis();
LOG.info("FOLLOWING - LEADER ELECTION TOOK - " +
(self.end_fle - self.start_fle));
self.start_fle = 0;
self.end_fle = 0;
fzk.registerJMX(new FollowerBean(this, zk), self.jmxLocalPeerBean);
try {
InetSocketAddress addr = findLeader();
try {
connectToLeader(addr);//连接到leader
long newEpochZxid = registerWithLeader(Leader.FOLLOWERINFO);
//check to see if the leader zxid is lower than ours
//this should never happen but is just a safety check
long newEpoch = ZxidUtils.getEpochFromZxid(newEpochZxid);
if (newEpoch < self.getAcceptedEpoch()) {
LOG.error("Proposed leader epoch " + ZxidUtils.zxidToString(newEpochZxid)
+ " is less than our accepted epoch " + ZxidUtils.zxidToString(self.getAcceptedEpoch()));
throw new IOException("Error: Epoch of leader is lower");
}
//跟leader进行数据同步 集群恢复后 leader-follower的数据同步 leader重新选举 进行数据同步
syncWithLeader(newEpochZxid); //跟leader进行数据同步
QuorumPacket qp = new QuorumPacket();
while (self.isRunning()) {
readPacket(qp);//不停从leader接收同步数据
processPacket(qp);
}
} catch (IOException e) {
LOG.warn("Exception when following the leader", e);
try {
sock.close();
} catch (IOException e1) {
e1.printStackTrace();
}
// clear pending revalidations
pendingRevalidations.clear();
}
} finally {
zk.unregisterJMX((Learner)this);
}
}