- 客户端的发送数据核心代码如下
org.apache.zookeeper.ClientCnxn.SendThread.run()
while (state.isAlive()) {
try {
if (!clientCnxnSocket.isConnected()) {
...
if (rwServerAddress != null) {
serverAddress = rwServerAddress;
rwServerAddress = null;
} else {
serverAddress = hostProvider.next(1000);
}
startConnect(serverAddress);
clientCnxnSocket.updateLastSendAndHeard();
}
...
sendPing();
clientCnxnSocket.updateLastSend();
} else {
if (timeToNextPing < to) {
to = timeToNextPing;
}
}
}
...
clientCnxnSocket.doTransport(to, pendingQueue, outgoingQueue, ClientCnxn.this);
}
这里是一个循环 只要是客户端没有被关闭 这个循环就会一直执行下去 主要的干的事情后有以下几件
- 根据启动时指定的zk集群地址(使用逗号分隔)挨个进行连接直到连接成功
- 连接成功后会修改一系列状态同时发布一些事件 然后触发心跳事件
private void sendPing() {
lastPingSentNs = System.nanoTime();
RequestHeader h = new RequestHeader(-2, OpCode.ping);
queuePacket(h, null, null, null, null, null, null, null, null);
}
触发心跳也是往即将要发送和的消息队列中塞入一个请求 这里并没有单独开一个线程来进行维护
- 最后一步就是具体的发送请求
这个流程解决了我的一些疑惑:
客户端连接zk集群的时候,指定了多个地址,具体应该去使用哪个地址,还有集群的leader挂了之后 如何去找其他可用的服务。通过上面的代码可知,这个循环在每次都会检查是否和服务端建立连接,如果没有建立 那么就一个一个地址挨个试,事实上zk集群的服务端,只有leader节点是可以和客户端建立连接的 因为只有leader会执行和startup方法,其他的都是节点都是被动跟着leader一起动的,leader挂了之后会选举出新的节点,新的主节点会执行startup方法接受客户端的连接