kafkaProducer 流程解读

395 阅读3分钟

一.流程图解

image.png

二.消息发送过程

1. 拦截器

image.png

2. 序列化器

serializedValue = valueSerializer.serialize(record.topic(), record.headers(), record.value());

这里会使用生产者客户端程序里设置的序列化方式进行序列化

3. 分区器

image.png

如果设置了分区就用设置的值,否则是可用分区中任意一个

4. 消息累加器

image.png

RecordAccumulator 中缓存的大小可以通过生产者客户端参数buffer.memory配置,默认值为 33554432B,即 32MB

RecordAccumulator的内部有一个BufferPool,它主要用来实现ByteBuffer的复用,以实现缓存的高效利用。不过BufferPool只针对特定大小的ByteBuffer进行管理,而其他大小的ByteBuffer不会缓存进BufferPool中,这个特定的大小由batch.size参数来指定,默认值为16384B,即16KB

在新建ProducerBatch时评估这条消息的大小是否超过batch.size参数的大小,如果不超过,那么就以batch.size 参数的大小来创建 ProducerBatch,这样在使用完这段内存区域之后,可以通过BufferPool 的管理来进行复用;

如果超过,那么就以评估的大小来创建ProducerBatch,这段内存区域不会被复用。 InFlightRequests保存对象的具体形式为Map<NodeId,Deque<Request>>,它的主要作用是缓存了已经发出去但还没有收到响应的请求(NodeId 是一个 String类型,表示节点的 id 编号)。

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

如果RecordAccumulator.RecordAppendResult满了或者newBatchCreated 则唤醒sender线程

5. Sender线程处理

Sender是一个实现了Runnable接口的线程类 此时看一下run()方法的具体处理内容

image.png

1.事物消息相关的处理流程/正常流程的数据发送准备 sendProducerData() 2.具体的数据发送过程 client.poll() 后面以这两个方法为主线分析

6. 创建网络请求实体

image.png 这里会把RecordAccumulator中 Map<分区ID, List> 转换为Map<NodeID, List> 便于向确定的Broker批量发送数据。

7. 缓存InflightRequest

addToInflightBatches(batches);

// A per-partition queue of batches ordered by creation time for tracking the in-flight batches

image.png

private final Map<TopicPartition, List> inFlightBatches;

这里缓存的是每一次的请求,此时,该请求未得到响应结果。本地数据处理好后,提交给selector处理。

8. 提交给Selector

sendProducerData->sendProduceRequest()

image.png

数据被放到KafkaChannel中,等待selecotr处理

9. Selector处理过程

image.png

selector.send()

image.png

可见,send()方法并没有对数据进行处理,只是获取一个可用KafkaChannel并且通过channel.send(send) 将该消息ID暂存,看一下send的实质内容

image.png

destinationId是消息唯一ID,至此,数据发送的准备工作完成。真正的发送通 client.poll()方法 相关类的类图关系如下:

未命名文件 (2).png

client.poll()在KafkaClient类中,从这里开始 NetworkClient 的 poll 方法内部会调用 Selector 执行就绪事件的选择,并将抽取的消息通过网络发送到 Broker 服务器,关于网络后面的具体实现,将在后续文章中单独介绍

10.响应

都知道,kafka producer发送消息有同步和异步的方式,关于同步和异步,这里解释下:

同步与异步同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。

根据上面的生产者发送消息的流程可知: producer 发送消息时候的同步和异步指的是生产者获得方法调用的响应机制,无论哪种方式,发送的消息都是通过sender线程异步发送到broker。 同步情况下,生产者阻塞在每一条消息的发送方法上,通过Future的结果获得响应。