Kafka 生产者模块(五):KafkaProducer 的 sender线程之NetworkClient#poll方法

本文详细分析了Kafka的NetworkClient如何处理网络请求和响应。主要流程包括:检查活跃状态、处理废弃的发送请求、更新集群元数据、发送网络请求、处理已完成的发送和接收、处理连接断开的情况、更新连接状态以及处理超时请求。在处理响应时,根据响应类型更新元数据、API版本信息,并调用用户提供的回调方法。整个过程确保了Kafka客户端高效、正确地与服务器交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       NetworkClient#poll 方法执行具体的网络请求和响应。下面来看一下 NetworkClient#poll 方法的具体实现:

public List<ClientResponse> poll(long timeout, long now) {
    ensureActive();

    if (!abortedSends.isEmpty()) {
        // If there are aborted sends because of unsupported version exceptions or disconnects,
        // handle them immediately without waiting for Selector#poll.
        List<ClientResponse> responses = new ArrayList<>();
        handleAbortedSends(responses);
        completeResponses(responses);
        return responses;
    }
    /*
     * 如果距离上次更新超过指定时间,且存在负载小的目标节点,
     * 则创建 MetadataRequest 请求更新本地缓存的集群元数据信息,并在下次执行 poll 操作时一并送出
     */
    long metadataTimeout = metadataUpdater.maybeUpdate(now);
    try {
        /* 发送网络请求 */
        this.selector.poll(Utils.min(timeout, metadataTimeout, defaultRequestTimeoutMs));
    } catch (IOException e) {
        log.error("Unexpected error during I/O", e);
    }

    // process completed actions
    /* 处理服务端响应 */
    long updatedNow = this.time.milliseconds();
    // 响应队列
    List<ClientResponse> responses = new ArrayList<>();
    // 对于发送成功且不期望服务端响应的请求,创建本地的响应对象添加到 responses 队列中
    handleCompletedSends(responses, updatedNow);
    /*
     * 获取并解析服务端响应
     * - 如果是更新集群元数据对应的响应,则更新本地缓存的集群元数据信息
     * - 如果是更新 API 版本的响应,则更新本地缓存的目标节点支持的 API 版本信息
     * - 否则,获取 ClientResponse 添加到 responses 队列中
     */
    handleCompletedReceives(responses, updatedNow);
    // 处理连接断开的请求,构建对应的 ClientResponse 添加到 responses 列表中,并标记需要更新集群元数据信息
    handleDisconnections(responses, updatedNow);
    // 处理 connections 列表,更新相应节点的连接状态
    handleConnections();
    // 如果需要更新本地的 API 版本信息,则创建对应的 ApiVersionsRequest 请求,并在下次执行 poll 操作时一并送出
    handleInitiateApiVersionRequests(updatedNow);
    // 遍历获取 inFlightRequests 中的超时请求,构建对应的 ClientResponse 添加到 responses 列表中,并标记需要更新集群元数据信息
    handleTimedOutRequests(responses, updatedNow);
    // 遍历处理响应对应的 onComplete 方法
    // 本质上就是在调用注册的 RequestCompletionHandler#onComplete 方法
    completeResponses(responses);

    return responses;
}

更新集群元数据

        首先来看更新本地缓存的集群元数据信息的过程( 步骤 1 ),前面曾多次提及到更新集群元数据的场景,而这些更新操作实际上都是标记集群元数据需要更新,真正执行更新的操作则发生在这里。实现位于 DefaultMetadataUpdater#maybeUpdate 方法中:

public long maybeUpdate(long now) {
    // should we update our metadata?
    // 获取下次更新集群信息的时间戳
    long timeToNextMetadataUpdate = metadata.timeToNextUpdate(now);
    // 检查是否已经发送了 MetadataRequest 请求
    long waitForMetadataFetch = hasFetchInProgress() ? defaultRequestTimeoutMs : 0;
    // 计算当前距离下次发送 MetadataRequest 请求的时间差
    long metadataTimeout = Math.max(timeToNextMetadataUpdate, waitForMetadataFetch);
    if (metadataTimeout > 0) {
        // 如果时间还未到,则暂时不更新
        return metadataTimeout;
    }

    // Beware that the behavior of this method and the computation of timeouts for poll() are
    // highly dependent on the behavior of leastLoadedNode.
    // 寻找负载最小的可用节点,如果没有可用的节点则返回 null
    Node node = leastLoadedNode(now);
    if (node == null) {
        log.debug("Give up sending metadata request since no node is available");
        return reconnectBackoffMs;
    }
    // 检查是否允许向目标节点发送请求,如果允许则创建 MetadataRequest 请求,并在下次执行 poll 操作时一并送出
    return maybeUpdate(now, node);
}
private long maybeUpdate(long now, Node node) {
    String nodeConnectionId = node.idString();
    // 如果允许向该节点发送请求
    if (canSendRequest(nodeConnectionId, now)) {
        Metadata.MetadataRequestAndVersion requestAndVersion = metadata.newMetadataRequestAndVersion();
        // 创建集群元数据请求 MetadataRequest 对象
        MetadataRequest.Builder metadataRequest = requestAndVersion.requestBuilder;
        log.debug("Sending metadata request {} to node {}", metadataRequest, node);
        // 将 MetadataRequest 包装成 ClientRequest 进行发送,在下次执行 poll 操作时一并发送
        sendInternalMetadataRequest(metadataRequest, nodeConnectionId, now);
        this.inProgressRequestVersion = requestAndVersion.requestVersion;
        return defaultRequestTimeoutMs;
    }
    /* 不允许向目标节点发送请求的场景 *
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值