Kafka生产者

2.Kafka生产者

2.1生产者流程

Kafka生产端(Produer)由两个线程完成消息的推送:

一个是主线程,用户端调用*kafkaProducer.send(ProducerRecord)*推送消息是通过主线程完成。推送的数据首先被缓存到双端队列消息累加器RecordAccumulator。

另外一个是sender IO线程,其不断轮询RecordAccumulator,满足一定条件后,就进行真正的网络IO发送,使用的是异步非阻塞的NIO。主线程的send方法提供了一个用于回调的参数,当sender线程发送完后,回调函数将被调用,可以用来处理成功,失败或异常的逻辑。

具体处理逻辑如下图所示:
在这里插入图片描述
Step1**:主线程工作

​ 在主线程,KafkaProducer调用send方法推送ProducerRecord创建的消息。该消息经过拦截器、序列化器、分区器最终加载到消息累加器。

拦截器:在消息发送前,可以按照某周规则过滤消息或者修改消息等。

序列化器:生产者需要用序列化器将key和value序列化成字节数组才可以将消息传入Kafka。

分区器:确定消息发送的分区,Kafka实现了不同的分区策略

消息累加器:主要用来缓存消息以便Sender线程可以批量读取、发送,进而减少网络传输的资源消耗来提升性能。 消息累加器是在客户端开辟出的一块内存区域,可以通过参数buffer.memory配置,默认值为 33554432B ,即 32M。RecordAccumulator的内部为每个分区都维护了一个双端队列。队列中的具体内容就是ProducerBatch(消息批次)。其中消息批次ProducerBatch,可以由多个较小的ProducerRecord(消息)组成。ProducerBatch大小可以通过batch.size控制,默认16kb。

Step2:消息加入消息累加器

分区器会为每条消息分配分区,确定分区的消息写入消息累加器时,会找到该分区对应的双端队列。在确定分区对应的双端队列以后,会向双端队列尾部的ProducerBatch加入消息。该操作执行完以后,主线程就只需要等待Sender线程轮询读取消息并执行返回结果。

Step3:Sender线程读取消息及消息发送

Sender线程不断轮询消息累加器,寻找达到发送要求的分区 。如:在分区中ProducerBatch内数据积累到batch.size(16kb),或者如果分区中ProducerBatch内数据迟迟未达到batch.size,Sender线程等待linger.ms设置的时间到了之后也会获取数据。linger.ms单位ms,默认值是0ms,表示没有延迟。

将轮询获得的各个ProducerBatch按照目标分区所在的leader broker进行分组

将分组后的batch通过底层创建的Socket连接发送给各个Kafka实例

请求在从 sender程发往 Kafka前还会保存到 InFlightRequests中,它的主要作用是缓存了已经发出去但还没有收到服务端响应的请求。InFlightRequests默认每个分区下最多缓存5个请求,可以通过配置参数为max.in.flight.request.per. connection修改。

等待服务器端发送response回来

Step4:Sender线程处理响应

发送后,需要等待kafka的应答机制,取决于配置项ack。Request请求接受到kafka的响应结果,如果成功的话,从InFlightRequests清除请求,否则的话需要进行重发操作,可以通过配置项retries决定,当消息发送出现错误的时候,系统会重发消息。retries表示重试次数。默认是 int 最大值,2147483647。

Step5:清除消息累加器消息

2.2Kafka生产者如何保证发送的消息不丢

消息丢失原因:网络延迟、或者Kafka实例宕机都会导致消息的丢失

Kafka通过ack确认机制来感知消息有没有丢失,通过合理设置ack可以确保消息不丢

ack确认机制分为三个级别:
在这里插入图片描述
ack=0:此时消息发送出去,生产者就不管消息了。即使消息因网络问题未发送到Kafka实例。此时效率最高,但安全性最低。
在这里插入图片描述
ack=1:生产者发送消息后,当Leader接受到消息会向生产者发送确认信息,确认消息已经发送成功。生产者收到效应后会清除消息累加器中的消息。当follower副本还没同步Leader副本中消息时,Leader宕机,此时数据也会丢失。
在这里插入图片描述
ack=-1或者ALL:生产发送消息后,当Leader收到消息和ISR中所有副本都同步到消息后才像生产者发送确认消息,确认消息已经发送成功。生产者收到效应后会清除消息累加器中的消息。此时数据在多个副本都存在,几乎不会丢失。

2.3Kafka生产者如何保证发送的消息只发一次

消息多发原因:在消息发送后,需要接受Kafka实例发来的确认信号。如果确认信号丢失、或者未在规定时间返回,此时生产者会认为消息没有发送成功。此时会重发消息,就会造成消息重复。对应三种情况。

最多一次(At Most Once),此时ack=0可以保证消息不重复(仅发送一次消息),但数据会丢失。

至少一次(At Least Once),此时ack=-1且分区副本大于等于2且ISR里应答的最小副本数量大于等于2可能会出现至少一次的消息(消息多次发送)。例如Leader节点数据已经落盘,ISR中Follow节点数据未落盘时Leader宕机。此时会重发消息,Leader中消息重复。可以保证消息不丢,但不能保证消息不重复。

精确一次(Exactly Once),在至少一次基础上加幂等性计算。重复发送的消息会丢弃。可以保证消息不丢,且能保证消息不重复。

2.4Kafka生产者如何保证发送消息的有序

影响生产者持久化消息顺序性的数有两个,retries(重试次数)、max.in.flight.request.per.connection(生产者在收到kafka响应之前可以投递多少个消息到kafka实例中)。

当retries>0且max.in.flight.request.per.connection>1会产生顺序性问题。例如前一批次数据写入失败,重试完成前,后一批次消息先写入成功。那么消息顺序性就产生问题。在需要消息强顺序性时最佳实践是配置为retries>0且max.in.flight.request.per.connection=1(牺牲吞吐量,保证消息顺序)

2.5Kafka生产者分区策略

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值