Kafka生产者源码解析之三NIO

Kafka的NIO解析回顾回顾之前两篇介绍了KafkaProducer类send消息的具体过程,和RecordAccumulator类append消息的具体过程。这一条线路其实就算完了,可是总觉得还缺点什么。 RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializ...
摘要由CSDN通过智能技术生成

目录

Kafka生产者源码解析之一KafkaProducer
Kafka生产者源码解析之二RecordAccumulator
Kafka生产者源码解析之三NIO
Kafka生产者源码解析之四Sender
Kafka生产者源码解析之五小结

回顾

之前两篇介绍了KafkaProducer类send消息的具体过程,和RecordAccumulator类append消息的具体过程。这一条线路其实就算完了,可是总觉得还缺点什么。


 			RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializedKey,
                    serializedValue, headers, interceptCallback, remainingWaitMs);
            if (result.batchIsFull || result.newBatchCreated) {
   
                log.trace("Waking up the sender since topic {} partition {} is either full or getting a new batch", record.topic(), partition);
                this.sender.wakeup();
            }
            return result.future;
            

由上面代码可知append消息之后,唤醒了Sender线程,这就是第二条线路,所以接下来我们就来对此类一探究竟,因为似乎到现在我们也不知道消息最终去了哪里。只知道消息被写入到MemoryRecordsBuilder对象里的appendStream属性里了,这个属性是一个数据输出流。可是这跟NIO又有什么关系呢,别急,往下看。

线索

目前还不会画图,所以只能一步一步来说了,先大致说下流程,下面再详细介绍每一步的由来。

  1. KafkaProducer.sender 其实就是 Sender类,即调用了此类的wakeup方法。
  2. Sender.wakeup方法里面调用了 this.client.wakeup() ,client是NetworkClient类。
  3. NetworkClient.wakeup方法里调用了 this.selector.wakeup(); selector 其实是 org.apache.kafka.common.network 包里面的Selector类。
  4. Selector.wakeup方法里调用了 this.nioSelector.wakeup(); nioSelector 其实就是 java.nio.channels.Selector 类,即 NIO原生的选择器类,它是一个抽象类。windows系统的话这里是 WindowsSelectorImpl
  5. WindowsSelectorImpl.wakeup方法就是唤醒选择器的作用,其底层也是用的本地方法实现。

NIO核心组件之一Selector

对NIO不清楚的可以自学,毕竟是java源生的架构,网上资料很多,这里只单纯的结合kafka介绍NIO的用法,主要目的是更全面的认识Kafka
通过上面的线索可以知道,当我们用kafka的生产者发送消息的时候,除了消息会被追加到RecordAccumulator这个对象里之外,还会调用一个Sender的wakeup方法。

			// 不清楚的同学可以看上两篇博客
			RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializedKey,
                    serializedValue, headers, interceptCallback, remainingWaitMs);
            if (result.batchIsFull || result.newBatchCreated) {
   
                log.trace("Waking up the sender since topic {} partition {} is either full or getting a new batch", record.topic(), partition);
                this.sender.wakeup();
            }

此处的sender到底是什么呢,我们看下KafkaProducer 的构造器,里面通过configs初始化了很对对象,所以我只截取初始化 sender的部分。

 			this.errors = this.metrics.sensor("errors");
            this.sender = newSender(logContext, kafkaClient, this.metadata);
            String ioThreadName = NETWORK_THREAD_PREFIX + " | " + clientId;
            ...
	// 初始化sender方法
	Sender newSender(LogContext logContext, KafkaClient kafkaClient, Metadata metadata) {
   
        int maxInflightRequests = configureInflightRequests(producerConfig, transactionManager != null);
        int requestTimeoutMs = producerConfig.getInt(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG);
        ChannelBuilder channelBuilder = ClientUtils.createChannelBuilder(producerConfig);
        ProducerMetrics metricsRegistry = new ProducerMetrics(this.metrics);
        Sensor throttleTimeSensor = Sender.throttleTimeSensor(metricsRegistry.senderMetrics);
        // 我们创建kafkaproducer得时候只传了一个配置文件对象,所以这里new了一个NetworkClient对象
        KafkaClient client = kafkaClient != null ? kafkaClient : new NetworkClient(
        		// 创建一个org.apache.kafka.common.network.Selector对象
                new Selector(producerConfig.getLong(ProducerConfig.CONNECTIONS_MAX_IDLE_MS_CONFIG),
                        this.metrics, time, "producer", channelBuilder, logContext),
                metadata,
                clientId,
                maxInflightRequests,
                producerConfig.getLong(ProducerConfig.RECONNECT_BACKOFF_MS_CONFIG),
                producerConfig.getLong(ProducerConfig.RECONNECT_BACKOFF_MAX_MS_CONFIG),
                producerConfig.getInt(ProducerConfig.SEND_BUFFER_CONFIG),
                producerConfig.getInt(ProducerConfig.RECEIVE_BUFFER_CONFIG),
                requestTimeoutMs,
                ClientDnsLookup.forConfig(producerConfig.getString(ProducerConfig.CLIENT_DNS_LOOKUP_CONFIG)),
                time,
                true,
                apiVersions,
                throttleTimeSensor,
                logContext);
        int retries = configureRetries(producerConfig, transactionManager != null, log);
        short acks = configureAcks(producerConfig, transactionManager != null, log);
        // 返回Sender对象,这里得client就是上面new得NetworkClient对象
        return new Sender(logContext,
                client,
                metadata,
                this.accumulator,
                maxInflightRequests == 1,
                producerConfig.getInt(ProducerConfig.MAX_REQUEST_SIZE_CONFIG),
                acks,
                retries,
                metricsRegistry.senderMetrics,
                time,
                requestTimeoutMs,
                producerConfig.getLong(ProducerConfig.RETRY_BACKOFF_MS_CONFIG),
                this.transactionManager,
                apiVersions);
    }

由上面代码可知,
Sender.client = NetworkClient
NetworkClient.selecto r= org.apache.kafka.common.network.Selector
再看下方法得调用关系。

	// Sender类
	publ
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值