1、生产者消息缓存机制
生产者缓存机制的主要目的是将消息打包,减少网络IO频率。
Kafka生产者为了避免高并发请求对服务端造成过大压力,每次发消息时并不是一条一条发往服务端,而是增加一个高速缓存,将消息集中到缓存后,批量进行发送。这种缓存机制也是高并发处理时经常使用的一种机制。
Kafka的消息缓存机制涉及到KafkaProducer中的两个关键组件: accumulator 和 sender。
源码截图如下:
1.1、RecordAccumulator处理逻辑
RecordAccumulator,是Kafka生产者的消息累加器。KafkaProducer把要发送的消息先在ReocrdAccumulator中缓存起来,再分批发送给kafka broker。
在RecordAccumulator中,会针对每一个Partition,维护一个Deque双端队列,这些Dequeue队列基本上是和Kafka服务端的Topic下的Partition对应的。每个Dequeue里会放入若干个ProducerBatch数据。
KafkaProducer每次发送的消息,都会根据key分配到对应的Deque队列中。每个消息都会保存到队列中的某一个ProducerBatch中。消息分发的规则是由Partitioner组件完成。
主要涉及到两个参数:
- BUFFER_MEMORY_CONFIG,RecordAccumulator缓冲区大小。
- BATCH_SIZE_CONFIG, 缓冲区每一个batch的大小。
在配置类:
ProducerConfig.java
1.2、Sender处理流程
Sender是KafkaProducer中用来发送消息的一个单独的线程。每个KafkaProducer对象都对应一个sender线程。它负责将RecordAccumulator中的消息发送给Kafka。
Sender每次只获取RecordAccumulator中缓存内容,达到BATCH_SIZE_CONFIG
大小的ProducerBatch消息。如果消息比较少,ProducerBatch中的消息大小,在等待LINGER_MS_CONFIG
(默认值 0)时长后,还达不到BATCH_SIZE_CONFIG
的话,就直接将ProducerBatch中的消息读取出来。
Sender对读取出来的消息,以Broker为key,缓存到一个对应的队列当中。在队列中的消息称为InflightRequest。然后把这些消息发往Kafka对应的Broker中,直到收到Broker的响应,才会从队列中移除。
这些队列最多缓存MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION
(默认值 5)个请求。
注意:一批消息是没有先后顺序的。
最后,Sender会通过其中的一个Selector组件完成与Kafka的IO请求,并接收Kafka的响应。
1.3、一些优化建议
Kafka的生产者缓存机制是Kafka面对海量消息时非常重要的优化机制。
合理优化参数,对于Kafka集群性能提升是非常重要的。
- 如果消息体比较大,应该考虑加大
batch.size
,尽量提升batch的缓存效率。 - 如果Producer要发送的消息确实非常多,需要考虑加大
total.memory
参数,尽量避免缓存不够造成阻塞。 - 如果发现生产者发送消息比较慢,可以考虑提升
max.in.flight.requests.per.connection
参数,加大消息发送的吞吐量。
2、发送应答机制
在Producer把消息发送到Broker后,如何确定消息是否成功送达?
是通过在Producer端,设置属性acks
。
acks
属性的作用是保证消息的安全性,尤其是在replica-factor
备份因子比较大的Topic中。
acks
属性三个值:
-
acks=0
-
生产者不关心Broker端是否将消息写入到Partition。
-
只发送消息,不关心应答。
-
吞吐量最高,数据安全性最低。
-
-
acks=all 或 -1
-
生产者需要等Broker端的所有Partiton都写完才返回结果。
-
即Leader Partition以及其对应的Follower Partition都写完了,才能得到返回结果。
-
数据最安全,吞吐量最低。因为每次发消息需要等待更长的时间。
-
-
acks=1
-
一种相对中和的策略。
-
Leader Partition在完成自己的消息写入后,就向生产者返回结果。
-
2.1、代码实验
在消息生产者的demo代码加入acks属性代码,进行测试
// 参数值按测试需求变化而变
props.put(ProducerConfig.ACKS_CONFIG, "1");
当设置acks=0
时,代码运行效果:
当设置acks=all
时,代码运行效果:
当设置acks=1
时,代码运行效果:
从上面运行效果截图来年,当acks=0
时,消息发送者拿不到offset的值。
参数设置建议:
acks=0
,可靠性太差,很少使用。acks=1
,一般用于传输日志等,允许个别数据丢失的场景。使用范围最广。acks=all或-1
,一般用于传输敏感数据,比如与钱相关的数据。
补充说明:
如果acks=all或-1
,Kafka并不是强制要求所有Partition都写入数据后才响应。
在Kafka的Broker服务端有一个配置参数min.insync.replicas
,控制Leader Partition在完成多少个Partition的消息写入后,向Producer返回响应。
这个参数可以在config/server.properties文件中进行配置。
3、我的公众号&资料获取
敬请关注我的公众号:大象只为你,持续更新技术知识…
相关资料获取:
如需SpringKafka项目Demo,请后台回复:【springkafka】。
我的代码是基于SpringBoot3.x上写的,IDEA 2024版