NetworkClient是一个网络客户端实现,它可以用于生产者发送消息,也可以用于消费者消费消息以及服务器端broker之间的通信
一 核心字段
Selectable selector: 用于执行网络I/O
MetadataUpdater: 用于更新Metadata
ClusterConnectionStates connectionStates: 每一个node的连接状态
InFlightRequests: 缓存发送请求但是还没有收到响应的队列
int socketSendBuffer:发送请求的缓冲区大小
int socketReceiveBuffer: 接收响应的缓冲区大小
String clientId: 客户端唯一标示
int requestTimeoutMs:生产者等待服务器端确认消息的超时时间
二 重要方法
2.1 ready 检测是否可以发送请求
public boolean ready(Node node, long now) {
// 检测节点是否为空
if (node.isEmpty())
throw new IllegalArgumentException("Cannotconnect to empty node " + node);
// 判断是否已经准备好发送请求
if (isReady(node, now))
return true;
// 检测该节点现在是否能够连接
if (connectionStates.canConnect(node.idString(), now))
// 初始化一个连接
initiateConnect(node, now);
return false;
}
public boolean isReady(Node node, long now) {
// 是否我们现在需要更新元数据以及该node是否已经可以发送请求
return !metadataUpdater.isUpdateDue(now) && canSendRequest(node.idString());
}
2.2 send 发送请求
public void send(ClientRequest request, long now) {
// 获取发送请求的目的地
String nodeId = request.request().destination();
// 如果该节点不能发送请求,则抛出异常
if (!canSendRequest(nodeId))
throw new IllegalStateException("Attempt to send a request to node " + nodeId + " which is not ready.");
doSend(request, now);
}
private void doSend(ClientRequest request, long now) {
request.setSendTimeMs(now);
// 将请求添加到等待响应的inFlightRequests队列
this.inFlightRequests.add(request);
// 发送请求
selector.send(request.request());
}
2.3 poll 进行网络I/O操作
public List<ClientResponse> poll(long timeout, long now) {
// 更新元数据请求
long metadataTimeout = metadataUpdater.maybeUpdate(now);
try {
// 执行I/O操作
this.selector.poll(Utils.min(timeout, metadataTimeout, requestTimeoutMs));
} catch (IOException e) {
log.error("Unexpected error during I/O", e);
}
// 处理完成的行为
long updatedNow = this.time.milliseconds();
List<ClientResponse> responses = new ArrayList<>();
handleCompletedSends(responses, updatedNow);// 处理completedSends队列
handleCompletedReceives(responses, updatedNow);// 处理completedReceivess队列
handleDisconnections(responses, updatedNow);//处理disconnect列表
handleConnections();//处理connect列表
handleTimedOutRequests(responses, updatedNow);// 处理InflightRquest中超时请求
// 循环调用ClientRequest的回调函数
for (ClientResponse response : responses) {
if (response.request().hasCallback()) {
try {
response.request().callback().onComplete(response);
} catch (Exception e) {
log.error("Uncaught error in request completion:", e);
}
}
}
return responses;
}
2.4 handleCompletedSends
我们知道completedSends保存的是最近一次poll发送成功的请求
private void handleCompletedSends(List<ClientResponse> responses, long now) {
// 遍历completedSends集合
for (Send send : this.selector.completedSends()) {
// 获取指定队列的第一个元素
ClientRequest request = this.inFlightRequests.lastSent(send.destination());
if (!request.expectResponse()) {// 检测请求是否需要响应
// 不需要的话将inFlightRequests队列中的第一个请求删除
this.inFlightRequests.completeLastSent(send.destination());
// 生成ClientResponse对象添加到response集合
responses.add(new ClientResponse(request, now, false, null));
}
}
}
2.5 handleCompletedReceives
private void handleCompletedReceives(List<ClientResponse> responses, long now) {
for (NetworkReceive receive : this.selector.completedReceives()) {
String source = receive.source();
// 从inFlightRequests队列中取出对应的ClientRequest
ClientRequest req = inFlightRequests.completeNext(source);
// 解析响应
Struct body = parseResponse(receive.payload(), req.request().header());
// 处理response,会更新metadata元数据,并唤醒所有等待metadata
// 更新完成的线程
if (!metadataUpdater.maybeHandleCompletedReceive(req, now, body))
// 如果不是MetadataResponse,则创建ClientResponse并添加到responses集合
responses.add(new ClientResponse(req, now, false, body));
}
}
2.6 handleDisconnections
private void handleDisconnections(List<ClientResponse> responses, long now) {
// 更新连接状态,并清理掉inFlightRequests中断开连接的Node对应的ClientRequest
for (String node : this.selector.disconnected()) {
log.debug("Node {} disconnected.", node);
processDisconnection(responses, node, now);
}
if (this.selector.disconnected().size() > 0)
metadataUpdater.requestUpdate(); // 标识需要更新集群元数据
}
2.7 handleConnections
private void handleConnections() {
// 遍历connect列表,将ConnectionStates中记录的连接状态修改为CONNECTed
for (String node : this.selector.connected()) {
log.debug("Completed connection to node {}", node);
this.connectionStates.connected(node);
}
}
2.8 handleTimedOutRequests
private void handleTimedOutRequests(List<ClientResponse> responses, long now) {
// 获取inFlightRequests中超时的请求
List<String> nodeIds = this.inFlightRequests.getNodesWithTimedOutRequests(now, this.requestTimeoutMs);
// 遍历这些超时的请求
for (String nodeId : nodeIds) {
// 关闭连接
this.selector.close(nodeId);
log.debug("Disconnecting from node {} due to request timeout.", nodeId);
processDisconnection(responses, nodeId, now);
}
// 更新元数据
if (nodeIds.size() > 0)
metadataUpdater.requestUpdate();
}