Java KafkaProducer冲洗不会阻塞主线程

Java KafkaProducer冲洗不会阻塞主线程,java,apache-kafka,kafka-producer-api,Java,Apache Kafka,Kafka Producer Api,对于org.apache.kafka.clients包中的KafkaProducer类,我有一个有趣的时刻。 根据文档,flush()方法的执行应该会阻止代码执行,直到发送完所有消息 我有这样的代码: messageSender.flush(); messageSender.close(); 方法messageSender.flush()为我的所有生产者执行flush: public void flush() { producers.forEach(Producer::flus

对于org.apache.kafka.clients包中的KafkaProducer类,我有一个有趣的时刻。 根据文档,flush()方法的执行应该会阻止代码执行,直到发送完所有消息

我有这样的代码:

messageSender.flush();
messageSender.close();
方法messageSender.flush()为我的所有生产者执行flush:

public void flush() {
        producers.forEach(Producer::flush);
    }

在执行第一个代码块之前,我通过send()方法发送一些消息。 但在结束之后,我发现,并非所有的消息都是在制作人关闭之前发送的

如果我将第一个代码块更改为:

messageSender.flush();
try {
    Thread.sleep(500);
} catch (InterruptedException e) {
    e.printStackTrace();
}
messageSender.close();
所有消息都已发送

我做错了什么

我的制作人有这样的配置:

(ProducerConfig.BATCH_SIZE_CONFIG, "65536");
(ProducerConfig.ACKS_CONFIG, "0");
(ProducerConfig.LINGER_MS_CONFIG, "40");
(ProducerConfig.COMPRESSION_TYPE_CONFIG, "lz4");
齐平

您的主线程不会被
producer.flush()阻塞太长时间,
这是因为使用
0
作为
ACK
,生产者的行为更像是
UDP
发送者:如果调用了sent,则消息成功完成,没有任何保证。因此,在使用此配置接收到机制之前,没有真正的块,并且通过
flush
清空的缓冲区几乎已经是空的


关闭

另一个应该阻止主线程直到发送are消息的方法是
close()
方法。从文档中:

close()

此方法将阻止,直到所有以前发送的请求完成


根据这个逻辑,您说的代码应该等到所有消息发送后再执行是正确的。配置中的问题似乎是
ACKS=0
属性

ACKs

值为0时,生产者甚至不会等待来自的响应 经纪人它立即认为编写成功 记录将被发送出去

可能发生的情况是:
close()
将等待所有请求完成,但如果ACK为0,则会对成功发送的消息撒谎。
生产者不会等待确认,因此会假定每条消息都已正确发送;然后将立即执行
close()
操作,而不会真正保证已完成的请求。在正常情况下,这将主要影响最后发送的请求


我会尝试的是:

  • ACKs=1
    (至少)
这将使
flush()
close()
再等待一段时间,因为生产者需要来自代理的ack才能将请求标记为成功

  • producer.close(500,时间单位。毫秒)
等待生产者完成所有未完成请求的发送,直到超时。这也将有助于处理这些最后的信息,并且是“官方”的方式来做你正在用你的睡眠手动做的事情。将其设置为所需的等待时间

  • 重复使用相同的
    生产者
不仅在中推荐,而且有助于提高总体性能

生产者是线程安全的,跨线程共享单个生产者实例通常比拥有多个实例更快


多谢各位!由于吞吐量的原因,我得到了ack=0。我正在对使用Kafka数据的服务执行一种性能测试。那么,您能纠正我吗,ack=1只会增加close()方法执行的延迟,或者所有发送通常都会变慢?是的,每个请求的完成都会变慢,而且如果设置了
重试次数,您会注意到对代理进行了更多的调用,以便将消息标记为正确发送。一般来说,这意味着通常的发送流需要一些额外的延迟,以及
flush()
close()
需要一些额外的时间来完成。这更像是从
UDP
转换为更常见的
TCP
send您不需要多个生产者实例。它们是线程安全的我知道,它们是线程安全的。但一个实例的吞吐量对于我的需求来说太低了。