NetworkClient分析

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();
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值