【配置篇】kafka生产者配置详细分析[全网最详细,最深度分析。持续补充中.....]

1.batch.size:批量消息大小。默认值是16K
源码注释翻译:
无论何时出现多个消息发往同一分区。生产者将尝试将消息进行打包用批处理方式来达到更少的请求。有助于提升客户单和服务器的性能。该项配置控制的是批量消息字节大小,不会尝试(发送)大于此配置的消息批次。发往broker的请求包含多个批量消息。每个broker分区对应一个数据分区(存放batch分区)。
较小的批量消息不太常见,并且可能降低吞吐量,该配置设置为0,将完全禁用批量处理。较大的设置,将会浪费更多的内存,因为我们总是按照设置的值来开辟预期的缓冲区。
分析:
batch.size表示的是批量消息大小。主线程将消息放进缓存,经过整理发往同一分区的消息被放进双端队列,当缓存中消息堆积达到batch.size,那么就会被sender线程发送。
但这不是绝对的;
从send方法源分析中我们知道当batchIsFull或者新建的batch,那么都会进行发送。详细见
发送消息send方法源码解读

向双端队列追加消息,会判断空间是否充足,如果不充足将会向内存池BufferPool申请开辟一个buffer,开辟的大小是batch.size,但是如果这个消息大小本身超过了batch.size,只要没有超过缓存总大小(buffer.memory的配置值)就按照消息本身的大小开辟buffer,然后进行发送。如果空间充足会进行尝试追加,然后判断是否达到了batch.size。
如果该配置设置为0,那么将不会出现批量发送,一个消息将发送一次。
该配置通常与linger.ms配置搭配使用.如果仅仅配置了该配置,没有配置linger.ms,很多时候也是无用的。

2.linger.ms:延迟发送时间毫秒值,默认值0
源码注释翻译:
生产者将两个请求之间的任何消息记录整合成一个消息批次形成一次批量处理请求。通常情况下,只有主线程放入缓存的速率大于sender线程的发送速率,才会发生了批量发送。但是在某些情况下,即使在负载不高的情况下,客户端仍然想实现批量发送。此设置通过添加人工延迟来实现这一点,就是消息不立即发送,通过延迟的方式来实现消息累积的效果。此设置给出了延迟的上限。
一旦累积的消息达到了 batch.size,无论此设置如何。那么将会立即发送。 但是ProducerBatch中累积的消息小于batch.size时候,将会在此设置的时间内,形成消息的累积。此设置默认为0(即无延迟)。设置LINGER_MS_CONFIG = 5 ,会在没有负载的情况下为发送的记录增加5ms的延迟。
分析:
注释中已经说的很清楚,当batch.size和linger.ms任意一条件满足,即触发消息发送。
linger.ms和batch.size 一样都是对RecordAccumulator的设置参数。在producer核心构造方法中初始化RecordAccumulator时候通过构造注入batch.size和linger.ms配置。在RecordAccumulator的redy方法中进行判断。sender线程发送消息之前会调用RecordAccumulator的redy方法筛选出可以发送的节点信息。会对发送时机进行判断。
优先级是:batch.size是否满了–>linger.ms时间是否达到(准确的讲是否过期,见第4 :retry.backoff.ms的配置分析)–>bufferPool内存池是否没了—>是否有其他操作关闭缓存–>是否有线程在flush过程中。其中有一个满足就满足发送条件,将会对消息进行发送的后续操作。
其中bufferPool满了是为了释放内存,如果其关闭缓存的操作也会把未发完的消息进行发送,详细见。sender线程源码分析–1

3.retries:生产者重试次数,默认值是0,不进行重试。
源码翻译:
设置大于0的值,会导致客户端进行重新发送任何发送失败的消息记录。注意,该重试与客户端收到错误时重新发送记录没有什么不同。允许重试,但是没有将max.in.flight.requests.per.connection设置为1,将可能导致消息的顺序发生改变。因为如果两个批量消息发往同一分区,第一个批量消息发送失败,进行重试,但是第二个却发送成功了,那么第二个batch就会先被发送到服务器。
分析:
生产者发往kafka服务器。可能发生一些未知异常,可以通过重新发送。该配置就是配置重试的的最大次数。一直出现异常将会一直重试,直至达到该设定的重试最大值。然后放弃重试。返回生产者异常。
Kafka保证同一个分区中的消息是有序的。如果生产者按照一定的顺序发送消息,那么这些消息也会顺序地写入分区,进而消费者也可以按照同样的顺序消费它,但是由于Kafka的重试配置,会导致出现顺序不一致,但是通常我们也不会依赖于消息队列本身的机制来保障消息的顺序问题。所以该影响可以忽略。
该配置,在事务开启的情况下如果没有进行显示配置,将会无限重试。如果用户指定配置只能是大于0的配置值,具体可以查看KafkaProducer中的configureRetries方法。
retries配置是sender线程的配置,在KafkaProducer的核心构造方法中,初始化sender时候通过构造注入。重试是在sender线程中监听到失败将该批量消息放进RecordAccumulator缓存等待发送。

问题:重试的ProducerBatch是否还会受linger.ms配置影响 。

有三点需要注意:
1:并不是所有的失败都会重试。
2:失败是将消息从双端队列头部放入。
对于第一点:在重试范围内,是RetriableException类型的异常均进行重试,或者生产者配置了transactional.id,并且enable.idempotence配置的true(默认true)。才会进行重试。
对于第二点在发送消息是从RecordAccumulator中的双端队列的尾部取消息,失败重试是将消息从头部加入。等待sender线程的发送,如果队列存在其他批量消息,先发送其他的批量消息。也就是重试之间,其他消息仍然正常发送。

其中:RetriableException类型的异常有:
DisconnectException:连接断开异常,请求完成之前,服务器断开连接了。
NetworkException:发送请求时,产生与网络有关的IOException,比如当本地缓存的Kafka元数据过期,客户端向Kafka服务器请求更新元数据,但是请求了一个已经挂掉了的节点。
UnknownTopicOrPartitionException:服务器返回未知主题或者未知分区异常,也可能没有权限访问。
TimeoutException:请求超时异常。
KafkaStorageException:服务器储存数据异常
LeaderNotAvailableException:当出现新的leader正在选举中,未知leader错误,
以及其他服务器返回异常…

4.retry.backoff.ms:重试间隔毫秒值,默认值100
源码注释翻译:
尝试重试对给定主题分区的失败请求之前等待的时间。 这可以避免在某些故障情况下太过紧凑重复发送请求。

分析
重试间隔时间,避免了密集的重试,该配置也是RecordAccumulator配置,注意重试中的ProducerBatch不再受linger.ms配置的影响。在linger.ms中分析了一个消息是否满足发送条件中第二步判断:消息是否过期,这个过期好比游戏发送大招的冷却时间,可以认为:每次消息发送之后,需要一个冷却时间然后才能进行再次发送。而这个冷却时间的计算逻辑是:
1:获取当前冷却了多久:每个ProducerBatch内部都会记录一个上次发送的时间戳lastAttemptMs。使用当前时间-lastAttemptMs得出冷却时间。
2:应该冷却多久:
在重试中:冷却时间使用retry.backoff.ms配置,否则使用linger.ms
具体实现是:
ProducerBatch使用了一个AtomicInteger记录失败重试的次数 。失败重试的计数器。当计数器>0,说明在重试中。虽然判断了当冷却时间小于重试间隔才会使用该时间,实际就是使用该时间,
详细见ready源码分析

5.max.in.flight.requests.per.connection :单个连接的最大未确认请求数,默认值5

源码翻译:
客户端发送阻塞之前的单个连接最大未确认请求数。如果此设置为大于1并且发送失败,则由于重试(如果启用了重试),则存在重新排序消息的风险。
分析:

1:单个连接如何理解?
就是与某个node的连接。在Kafka-client中使用了Node抽象表示每个node节点使用Cluster表示Kafka集群服务器。而Cluster被Metadata持有,缓存从在客户端本地,默认5分钟强制更新一次。当然也会有其他操作会触发Metadata的更新。也就是发往同一node的消息批次,如果有超过5个未收到ack,那么将会发生阻塞。

2:该配置是配置的什么?
是网络层NetworkClient的请求队列InFlightRequest的长度限制。关于请求队列分析,详细查看【数据结构篇】请求队列InFlightRequest
InFlightRequest内部使用了一个hashmap存放请求,key是nodeId,value是一个双端队列,发往该node的请求都会存放在这个双端队列中。

3:何时进行校验:
检查一个node是否是ready状态,会对请求队列的是否满了进行校验。sender线程 将node节点从RecordAccumulator缓存中取出来进行发送消息,会遍历所有的node节点,进一步检查是否ready。
更新metadata时候让然会也会对请求队列的判断

注意:在幂等的条件下,该配置只能比默认配置小。当该配置设置为1的时候,表明未确认的请求只能有一个,当上一批消息未收到ack的时候。不会进行再次请求。注意请求跟消息的区别。所以改设置为1的时候能保证消息的顺序问题。从批量消息来看可以理解为批次串行化。注意跟同步发送的区别,可以认为批次同步发送。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值