拿五台机器4核,8G的机器做ZK集群举例子。
1.首先就是每台机器启动时,会给自己投票选举自己当老大。
synchronized(this) {
//logicalclock 值就是自己的进行选举的标号自增1,这个字段的取值就是配置文件中的server.X信息
++this.logicalclock;
//更新本地选举字段信息
this.updateProposal(this.getInitId(), this.getInitLastLoggedZxid(), this.getPeerEpoch());
}
2.发送投票信息给其他的服务器
private void sendNotifications() {
for (QuorumServer server : self.getVotingView().values()) {
long sid = server.id;
ToSend notmsg = new ToSend(ToSend.mType.notification,
proposedLeader,//通知其他人了的当前的leader是谁
proposedZxid, //当前最新的任务号
logicalclock, //当前选票最大的值
QuorumPeer.ServerState.LOOKING, //观察者模式
sid,
proposedEpoch);
if(LOG.isDebugEnabled()){
LOG.debug("Sending Notification: " + proposedLeader + " (n.leader), 0x" +
Long.toHexString(proposedZxid) + " (n.zxid), 0x" +Long.toHexString(logicalclock) +
" (n.round), " + sid + " (recipient), " + self.getId() +
" (myid), 0x" + Long.toHexString(proposedEpoch) + " (n.peerEpoch)");
}
sendqueue.offer(notmsg);
}
}
3.监听leader的指令(lookForLeader)
try {
roZkMgr.start();
setBCVote(null);
//这是一段单独的线程进行监控,也就是一直说的zk心跳检测
setCurrentVote(makeLEStrategy().lookForLeader());
} catch (Exception e) {
LOG.warn("Unexpected exception",e);
setPeerState(ServerState.LOOKING);
} finally {
// If the thread is in the the grace period, interrupt
// to come out of waiting.
roZkMgr.interrupt();
roZk.shutdown();
}
4.将发送的消息放置到消息队列中
private void sendNotifications() {
for (QuorumServer server : self.getVotingView().values()) {
long sid = server.id;
ToSend notmsg = new ToSend(ToSend.mType.notification,
proposedLeader,//通知其他人了的当前的leader是谁
proposedZxid, //当前最新的任务号
logicalclock, //当前选票最大的值
QuorumPeer.ServerState.LOOKING, //观察者模式
sid,
proposedEpoch);
if(LOG.isDebugEnabled()){
LOG.debug("Sending Notification: " + proposedLeader + " (n.leader), 0x" +
Long.toHexString(proposedZxid) + " (n.zxid), 0x" + Long.toHexString(logicalclock) +
" (n.round), " + sid + " (recipient), " + self.getId() +
" (myid), 0x" + Long.toHexString(proposedEpoch) + " (n.peerEpoch)");
}
sendqueue.offer(notmsg);//存放消息队列
}
}
5.进行消息的发送
synchronized void connectOne(long sid){
if (senderWorkerMap.get(sid) == null){
InetSocketAddress electionAddr;
if (self.quorumPeers.containsKey(sid)) {
electionAddr = self.quorumPeers.get(sid).electionAddr;
} else {
LOG.warn("Invalid server id: " + sid);
return;
}
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Opening channel to server " + sid);
}
Socket sock = new Socket();//底层的zk就是sock长连接
setSockOpts(sock);
sock.connect(self.getView().get(sid).electionAddr, cnxTO);//获取配置文件的其他集群的ip地址
if (LOG.isDebugEnabled()) {
LOG.debug("Connected to server " + sid);
}
initiateConnection(sock, sid);
} catch (UnresolvedAddressException e) {
// Sun doesn't include the address that causes this
// exception to be thrown, also UAE cannot be wrapped cleanly
// so we log the exception in order to capture this critical
// detail.
LOG.warn("Cannot open channel to " + sid
+ " at election address " + electionAddr, e);
throw e;
} catch (IOException e) {
LOG.warn("Cannot open channel to " + sid
+ " at election address " + electionAddr,
e);
}
} else {
LOG.debug("There is a connection already for server " + sid);
}
}