kafka05-Sender线程消息发送时机和发送流程

目录

KafkaProducer客户端三大重要组件

RecordAccumulator 中的消息发送时机

Sender 发送消息流程


KafkaProducer客户端三大重要组件

在KafkaProducer客户端中,有三个关键组件协同工作来完成消息的发送:

  1. KafkaProducer

    • 这是用户与Kafka Producer交互的主要接口。通过调用KafkaProducer.send()方法,用户可以将消息封装为ProducerRecord对象发送到Kafka集群。
    • KafkaProducer负责序列化消息的Key和Value,并将它们封装成ProducerRecord对象。
  2. RecordAccumulator

    • RecordAccumulator是KafkaProducer内部的一个组件,它充当消息的缓冲区。当调用KafkaProducer.send()方法时,消息不是立即发送到Broker,而是先被缓存到RecordAccumulator中。
    • RecordAccumulator管理着一个内存池,用于存储多个ProducerBatch。它根据消息的TopicPartition将消息分批存储,并在适当的时候触发批量发送。
  3. Sender

    • Sender是一个后台运行的子线程,负责从RecordAccumulator中取出ProducerBatch并发送到Kafka集群的Broker上。
    • Sender线程会根据配置的参数(如batch.sizelinger.ms)来决定何时发送消息。它也负责处理来自Broker的响应,包括发送成功或失败的回调。

RecordAccumulator 中的消息发送时机

在Kafka Producer中,RecordAccumulator负责管理消息的缓存和批量发送。Sender线程通过特定的条件检查来确定何时从RecordAccumulator中获取并发送消息。以下是Sender线程判断消息是否就绪并发送到Broker的流程:

  1. 遍历batches

    Sender线程首先遍历RecordAccumulator中的batches,这是一个ConcurrentMap<TopicPartition, Deque<ProducerBatch>>,用于存储每个TopicPartition的消息批次(ProducerBatch)队列。
  2. 检查批次状态

    对于每个TopicPartition,Sender线程检查其对应的Deque<ProducerBatch>队列,找到队列头部的ProducerBatch
  3. 查找Leader

    根据TopicPartition信息,Sender线程查找其Leader副本所在的Broker节点。
  4. 未知Leader处理

    如果Leader信息未知(可能因为Leader变更或元数据未更新),则将该Topic添加到unknownLeaderTopics集合,并计划发送元数据更新请求。
  5. 判断发送条件

    Sender线程判断当前ProducerBatch是否满足发送条件,这包括:
    • transactionCompleting:是否事务正在完成。
    • flushInProgress():是否正在进行缓存刷新。
    • closed:Producer是否已关闭。
    • exhausted:是否所有批次都已发送,没有更多消息可发送。
    • waitedTimeMs >= timeToWaitMs:自批次创建以来的时间是否已达到或超过linger.ms配置的延迟。
    • batch.isFull():批次是否已满,达到batch.size配置的上限。
  6. 添加到readyNodes

    如果ProducerBatch满足发送条件,且其Leader不在readyNodes集合中,则将该Leader添加到readyNodes中,表示已准备好发送。
  7. 计算下次检查延迟

    如果ProducerBatch不满足发送条件,计算下一次检查的延迟时间,并更新nextReadyCheckDelayMs
  8. 发送消息

    对于所有在readyNodes中的Leader,Sender线程将从对应的ProducerBatch中获取消息并发送到Broker。
  9. 处理响应

    根据Broker的响应,Sender线程将处理消息发送的结果,包括成功确认或失败重试,并触发相应的回调。

Sender 发送消息流程

  1. 获取就绪批次

    Sender调用RecordAccumulator.drain()方法,获取一系列准备好的ProducerBatch列表。这些批次是根据readyNodes中的Broker节点分组的。
  2. 遍历Broker节点

    遍历nodes中的每个Broker节点,使用drainBatchesForOneNode()方法抽取对应Broker上的Leader分区副本中的批次。
  3. 抽取逻辑

    使用drainIndexstart变量来记录遍历的进度,确保从每个Broker的0号分区开始抽取。
  4. 获取Leader分区信息

    根据Broker ID获取所有Leader分区副本信息。
  5. 循环抽取

    循环遍历每个分区,从RecordAccumulator中抽取ProducerBatch
  6. 检查重试和大小限制

    如果ProducerBatch正在重试并且尚未达到退避时间(backoff),则跳过该分区。如果加上新批次后的消息总大小超过maxRequestSize,则结束当前批次的抽取。
  7. 关闭批次

    将满足条件的ProducerBatch加入到ready列表中,并关闭该批次,禁止再向其中追加新消息。
  8. 封装ProduceRequest

    ProducerBatch列表封装成一个或多个ProduceRequest,准备发送到Broker。
  9. 发送请求

    使用NetworkClient发送ProduceRequest到Broker节点。
  10. 管理InFlightRequests

    将发送的请求存储在InFlightRequests队列中,这个队列的大小受max.in.flight.requests.per.connection参数控制。
  11. 顺序保证

    如果enable.idempotence设置为true,Broker将保证请求的顺序处理。如果设置为false,则需要将max.in.flight.requests.per.connection设置为1以保证顺序。
  12. 处理响应

    KafkaProducer客户端通过Future处理来自Broker端的响应,包括发送成功或失败。
  13. 内存回收

    发送完成后,将ProducerBatch使用的ByteBuffer回收到BufferPool中,完成发送流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值