Kafka produce flush 引起的性能分析

文章分析了使用KafkaProducer发送数据时出现10-200ms延迟的原因,指出频繁调用flush方法导致缓存区清空过程中的线程堵塞,从而增加了IO等待时间。通过调整参数控制producer生产,避免手动频繁刷新缓存区,有效解决了延迟问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

调用kafka producer发送数据时,发现延迟级别在10-200ms不等,与正常的kafka写入速度不匹配,于是开始找问题~

一.场景:

一批数据,需要遍历每个数据并发送数据细节的信息到kafka,下面是我原始代码,每个人发送后执行一次flush操作。

val results = Array[DataObject](...)
results.foreach(data => {
    val info = new ProducerRecord[String, String](topic, message)
    producer.send(info)
})
kafka.flush()

服务器执行延迟在10-200ms不等

二.可能原因分析:

1.send 函数造成阻塞

    public Future<RecordMetadata> send(ProducerRecord<K, V> record) {
        return this.send(record, (Callback)null);
    }

    public Future<RecordMetadata> send(ProducerRecord<K, V> record, Callback callback) {
        ProducerRecord<K, V> interceptedRecord = this.interceptors == null ? record : this.interceptors.onSend(record);
        return this.doSend(interceptedRecord, callback);
    }

查看源码的send逻辑,一种有回调函数,一种没有回调函数,所以这里send是异步执行,不会造成堵塞,排除

2.flush 函数造成阻塞

    public void flush() {
        log.trace("Flushing accumulated records in producer.");
        this.accumulator.beginFlush();
        this.sender.wakeup();

        try {
            this.accumulator.awaitFlushCompletion();
        } catch (InterruptedException var2) {
            throw new InterruptException("Flush interrupted.", var2);
        }
    }

flush 这里accumulator会调用await相关方法,查看官方API的解释是:

flush()
Invoking this method makes all buffered records immediately available to send (even if linger.ms is greater than 0) and blocks on the completion of the requests associated with these records.

调用此方法可使所有缓冲记录立即可用于发送(即使linger.ms大于0)并在与这些记录关联的请求完成时发生阻塞。 ok,找到问题

三.Flush 原理

基于flush引起的延迟,首先看一下kafka生产的过程

Step1:异步调用send发送日志,根据Properties的配置对kv进行序列化

Step2::根据k hash 得到分区信息,追加到对应topic下的partition,这里先会写入到本地缓存区

Step3: 本地缓存写入后,有独立的线程传送向producer发送ACK

1.分析:

flush 是将第二步写到缓存区的数据强制推送发送,正常情况下清空缓存区操作通过参数配置实现:

batch.size 离线缓存达到该size时执行一次flush

linger.ms 达到该时间间隔时,执行一次flush

调用flush时,会清空缓存区内存,调用 awaitFlushCompletion 时需要等待缓存区清空,这里会造成线程的堵塞

    public void awaitFlushCompletion() throws InterruptedException {
        try {
            Iterator i$ = this.incomplete.all().iterator();

            while(i$.hasNext()) {
                RecordBatch batch = (RecordBatch)i$.next();
                batch.produceFuture.await();
            }
        } finally {
            this.flushesInProgress.decrementAndGet();
        }

    }

awaitFlushCompletion 将当前缓存区数据构造迭代器循环发送,并在finally阶段调整offset。

这里我设置发送延迟时间为1000ms

我的实际发送时间在1000ms以内,所以每次发送调用 flush 都会造成延迟,相当于手动调用频繁的刷新缓存区,增加的IO等待的时间,违背了批处理减少IO的规则,所以造成kafka写入时长增加,这里取消flush,通过参数控制 producer 生产解决问题。

第一次时间长是因为初始化kafka服务端,和最一开始添加 flush 相比,时间消耗基本可以忽略。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIT_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值