kafka14-kafka生产者延迟原理及优化

目录

1.Kafka生产者端出现延迟的原因

2.消息分区策略

RoundRobin分区策略

Network Thread的任务

linger.ms的影响

max.request.size的作用

为什么建议一个发送请求包含多条记录

Sticky分区策略

开启Sticky分区策略

Partitioner接口的变更

DefaultPartitioner的实现

KafkaProducer中的处理流程

代码示例

性能提升

3.误区:linger.ms=0 只产生单记录批次

实际行为


1.Kafka生产者端出现延迟的原因

Kafka生产者端出现延迟的原因可以归结为多个方面

  1. 元数据获取延迟:生产者在发送消息前需要确定目标分区的Leader副本。这需要通过获取主题的元数据来实现。如果元数据获取过程耗时过长,尤其是在max.block.ms参数设定的时间内无法完成,生产者将无法发送消息,从而导致延迟。

  2. 网络请求开销:每次发送消息,生产者都需要与Broker建立网络连接。如果生产者频繁发送单条消息,这将导致大量的网络开销,降低消息发送的效率。

  3. RecordBatch 累积机制:为了减少网络请求,生产者会将多条消息累积到一个RecordBatch中。这个过程由batch.size参数控制。如果RecordBatch设置得过小,即使消息生成速率不高,也可能导致频繁的网络请求,从而增加延迟。

  4. Linger时间设置linger.ms参数决定了生产者在发送消息前等待更多消息的时间。如果设置为0,生产者将尽可能快地发送消息,但这可能导致RecordBatch未填满就发送,降低了网络效率。如果设置得过高,生产者会等待更长时间以填满RecordBatch,这可能会增加延迟,但可以提高吞吐量。

  5. 压缩策略:启用压缩可以减少发送到Broker的数据量,降低网络带宽的使用。然而,压缩和解压缩过程会增加CPU负载,可能会对消息发送的延迟产生影响。

  6. 生产者配置:其他生产者配置,如buffer.memory(控制生产者可以缓冲的消息的最大字节数)和acks(控制消息确认的级别),也会影响消息的发送和确认机制,进而影响延迟。

  7. Broker负载:Broker的负载情况也会影响消息的发送。如果Broker正在处理大量请求,它可能无法及时响应生产者的请求,导致延迟。

  8. 主题分区和副本策略:主题的分区数和副本因子也会影响延迟。更多的分区可以提供更高的并行处理能力,但同时也增加了协调副本之间的开销。副本因子的增加可以提高数据的可靠性,但也会增加写入的延迟。

2.消息分区策略

在Kafka v2.3版本以前,RoundRobin分区策略是一种简单的数据分发机制,它在没有key的情况下将消息均匀地分配到各个分区。

RoundRobin分区策略

  • 均匀分配:RoundRobin策略通过循环遍历分区列表,将连续的消息发送到不同的分区,实现负载均衡。
  • 批次增多:由于RoundRobin策略在每个分区中轮流发送消息,当linger.ms参数设置为正值时,可能会导致每个批次中的消息数量减少,甚至出现单个消息的批次。

Network Thread的任务

  1. 检查Broker状态:Network Thread不断检查Broker节点状态,以获取健康的TopicPartition列表。
  2. 转换RecordBatch:将RecordBatch从Map<TopicPartition, Deque<RecordBatch>>转换为Map<brokerID, List<RecordBatch>>,以便按Broker分组发送。
  3. 发送和清理:将分组后的RecordBatch发送到对应的Broker,并在传输完成后清理Map数据。

linger.ms的影响

  • linger.ms大于0时,Network Thread会等待,直到RecordBatch填满或超时,而不是立即发送,这有助于增加每个批次的消息数量,减少网络请求。

max.request.size的作用

  • max.request.size限制了生产者单个发送请求的最大字节数,有助于控制请求的大小,避免过大的请求对网络和Broker造成压力。

为什么建议一个发送请求包含多条记录

  • 减少数据包数量:包含多条记录的请求减少了数据包的数量,降低了网络开销。
  • 减少元数据解析工作量:每个数据包都需要解析报头等元数据,多条记录的请求减少了这种解析的工作量。
  • 提高Broker存储效率:在Broker端,xx.index文件会记录消息的偏移量和位置,包含多条记录的批次可以在xx.index中记录更大范围的消息,提高索引效率。
  • 加速消费者端数据搜索:消费者在搜索数据时,可以更快地定位到消息,因为xx.index中记录了更多消息的位置信息。

在Apache Kafka 2.4版本中引入的Sticky分区策略,旨在改善当消息的key为null时的分区效率和降低延迟。以下是对Sticky分区策略的详细解释和分析:

Sticky分区策略

  • 目的:Sticky分区策略通过将连续的消息尽可能发送到同一个分区,减少批次的数量,从而提高批处理效果和降低延迟。
  • 工作原理:当key为null时,Sticky分区策略会选择一个分区发送所有记录,直到该分区的RecordBatch已满。然后,它会随机选择一个新的分区,并“粘附”到这个新分区上,直到下一个RecordBatch也满了。

开启Sticky分区策略

  • 在Kafka 2.4及以后版本,默认已经开启了Sticky分区策略。如果需要显式设置,可以在生产者配置中添加:
    props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, StickyAssignor.class.getName());

Partitioner接口的变更

  • Kafka 2.4在Partitioner接口中增加了onNewBatch方法,这个方法在创建新批次之前被调用,是实现Sticky分区策略的关键。

DefaultPartitioner的实现

  • DefaultPartitioner实现了onNewBatch方法,使用stickyPartitionCache来管理粘性分区的逻辑。

KafkaProducer中的处理流程

  1. 尝试追加消息:首先尝试向之前的分区追加消息。
  2. 追加失败处理:如果追加失败(因为RecordBatch已满),则需要选择新的分区,并新建一个RecordBatch。
  3. 触发新分区:调用onNewBatch()方法,使用RoundRobin策略选择新的分区。
  4. 获取新分区:通过分区器获取新的分区值。
  5. 封装TopicPartition:使用新分区值封装成TopicPartition对象。
  6. 再次追加消息:向新分区的RecordBatch中追加之前失败的消息。

代码示例

  • 以下是KafkaProducer中处理Sticky分区的伪代码示例:
    // 尝试向以前的分区写入消息
    RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializedKey,
            serializedValue, headers, interceptCallback, remainingWaitMs, true, nowMs);
    
    // 如果append()未成功,说明RecordBatch已满,需要新建RecordBatch
    if (result.abortForNewBatch) {
        int prevPartition = partition;
        // 调用onNewBatch()方法,触发新的分区
        partitioner.onNewBatch(record.topic(), cluster, prevPartition);
        // 获取新的分区值
        partition = partition(record, serializedKey, serializedValue, cluster);
        // 封装TopicPartition
        tp = new TopicPartition(record.topic(), partition);
        // 再次运行append()方法,这时会新建一个RecordBatch并将写入失败的消息追加到新的RecordBatch中
        result = accumulator.append(tp, timestamp, serializedKey,
            serializedValue, headers, interceptCallback, remainingWaitMs, false, nowMs);
    }

性能提升

  • 使用Sticky分区策略可以减少Network Thread发送请求的数量,提高Kafka发送消息的吞吐量。对于key不为null的情况,Sticky分区策略和RoundRobin分区策略的性能差异不大,但在key为null的场景下,Sticky策略可以显著提高吞吐量。

通过引入Sticky分区策略,Kafka进一步提升了生产者的性能,特别是在处理大量无key消息时,能够更有效地利用网络资源和减少延迟。

3.误区:linger.ms=0 只产生单记录批次

  • 常见误解:人们可能会认为,将 linger.ms 设置为 0 会导致生产者立即发送每条消息,从而产生大量单记录的批次。

实际行为

  1. 批量处理:即使 linger.ms=0,如果多条消息几乎同时到达并且目标分区相同,生产者会将它们组合成批一起发送,以减少网络请求次数。
  2. 处理时间:生产者在发送消息前需要进行一些内部处理,如等待序列化完成、压缩数据等。在这些处理完成之前,生产者会暂时保留消息,形成批次。
  3. 网络请求:网络请求本身也有最小延迟,即使立即发送消息,也可能不如批量发送高效。生产者会利用这一点,尽可能地将消息组合成批。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值