case FOLLOWING:
try {
LOG.info("FOLLOWING");
setFollower(makeFollower(logFactory));
follower.followLeader();
} catch (Exception e) {
LOG.warn("Unexpected exception", e);
} finally {
follower.shutdown();
setFollower(null);
updateServerState();
}
break;
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();
}
上一篇讲到进行了选举结束,那么每个节点的角色会确定,这一篇,看看follower和leader角色分别会做什么操作,先看leader
如果该服务器是leader角色,那么会调用makeLeader方法,这个方法里会new Leader,直接看Leader的构造函数
public Leader(QuorumPeer self, LeaderZooKeeperServer zk) throws IOException {
this.self = self;
this.proposalStats = new BufferStats();
Set<InetSocketAddress> addresses;
if (self.getQuorumListenOnAllIPs()) {
addresses = self.getQuorumAddress().getWildcardAddresses();
} else {
addresses = self.getQuorumAddress().getAllAddresses();
}
addresses.stream()
.map(address -> createServerSocket(address, self.shouldUsePortUnification(), self.isSslQuorum()))
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(serverSockets::add);
if (serverSockets.isEmpty()) {
throw new IOException("Leader failed to initialize any of the following sockets: " + addresses);
}
this.zk = zk;
}
可以看到这里是为每个ip创建ServerSocket,由此我们可以知道服务端之间的通讯是走的BIO。为什么这里走bio呢,因为zk服务端不多呀,撑死一个集群就10台-30台服务器吧,用bio处理是够用了。
创建好所有的ServerSocket后会调用lead方法,lead方法里面履行的是leader的职责,这里代码挺多的,总结一下,这坨代码做了以下几件事情。
1、zk.loadData()
2、开始LearnCnxAcceptor线程
3、设置一通QuorumVerifier(妈呀,这个玩意是干嘛的)
4、等待其他节点选举的ack
5、startZkServer()
6、上报心跳
这6个步骤里面最重要的是LearnCnxAcceptor线程了,我们来看看里面做的是什么操作
顾名思义,这个线程事接收follower节点请求的。
public void run() {
try {
Thread.currentThread().setName("LearnerCnxAcceptorHandler-" + serverSocket.getLocalSocketAddress());
while (!stop.get()) {
acceptConnections();
}
} catch (Exception e) {
LOG.warn("Exception while accepting follower", e);
if (fail.compareAndSet(false, true)) {
handleException(getName(), e);
halt();
}
} finally {
latch.countDown();
}
}
private void acceptConnections() throws IOException {
Socket socket = null;
boolean error = false;
try {
socket = serverSocket.accept();
// start with the initLimit, once the ack is processed
// in LearnerHandler switch to the syncLimit
socket.setSoTimeout(self.tickTime * self.initLimit);
socket.setTcpNoDelay(nodelay);
BufferedInputStream is = new BufferedInputStream(socket.getInputStream());
LearnerHandler fh = new LearnerHandler(socket, i