KafkaProducer send method都返回Future并接受回调。
在完成发送后使用一种机制而不是另一种机制执行操作之间是否有任何根本区别?
答案 0 :(得分:16)
异步方法
producer.send(record, new Callback(){
@Override
onComplete(RecordMetadata rm, Exception ex){...}
})
与同步相比,提供更好的吞吐量
RecordMetadata rm = producer.send(record).get();
因为你不会在第一种情况下等待确认。
同样以异步方式排序不能保证,而在同步中它是 - 只有在收到确认后才发送消息。
另一个区别可能是,在异常情况下同步调用中,您可以在发生异常后立即停止发送消息,而在第二种情况下,在您发现某些内容错误之前会发送一些消息执行一些行动。
另请注意,在异步方法中,消息的数量为#fl;"由max.in.flight.requests.per.connection
参数控制。
除了同步和异步方法,您可以使用 Fire和Forget 方法,这几乎与同步方法相同,但不处理返回的元数据 - 只需发送消息并希望它将到达经纪人(知道它很可能会发生,生产者会在可恢复错误的情况下重试),但有些消息可能会丢失:
RecordMetadata rm = producer.send(record);
总结:
答案 1 :(得分:12)
查看链接到它的文档看起来Future和Callback之间的主要区别在于谁发起了"请求已经完成,现在是什么?"问题
我们假设我们有一位客户C
和一位面包师B
。并C
要求B
让他成为一个不错的饼干。现在,面包师可以通过两种方式将美味饼干送回给顾客。
面包师接受请求并告诉客户:好的,当我完成后,我会把你的cookie放在柜台上。 (此协议是Future
。)
在这种情况下,客户负责检查柜台(Future
)以查看面包师是否已完成其cookie。
<强>阻断强> 顾客呆在柜台附近看着它,直到把饼干放到那里(Future.get())或者面包师在那里道歉(错误:饼干面团外)。
<强>非阻塞强> 客户做了一些其他的工作,偶尔检查一下cookie是否在柜台上等待他(Future.isDone())。如果cookie准备就绪,则客户接受它(Future.get())。
在这种情况下,顾客在订购饼干后告诉面包师:当我的饼干准备好后,请把它交给我的宠物机器人狗,他会知道该怎么做(这个机器人就是回调)。
现在,当饼干准备好时,面包师会给狗狗饼干并告诉他回到它的主人那里。面包师可以继续为另一位顾客烘焙下一个饼干。
狗跑回顾客并开始摆弄它的人造尾巴,让顾客知道他的饼干准备好了。
注意顾客如何知道什么时候会给他饼干,他也不会主动调查面包师是否准备好。
这是两个场景之间的主要区别。谁负责发起你的cookie准备好了,你想用它做什么?&#34;题。对于未来,客户有责任通过积极等待或偶尔轮询来检查何时准备就绪。如果回调,面包师将回叫所提供的功能。
我希望这个答案能让您更好地了解未来和Calback的实际情况。一旦你掌握了一般的想法,你就可以尝试找出每个特定事物的处理方式。当线程被阻塞时,或者以什么顺序阻止一切完成。编写一些打印语句的简单程序,如:&#34;主客户端线程:cookie收到&#34;可能是一种有趣的实验方法。
答案 2 :(得分:2)
主要区别在于您是否要阻止等待确认的调用线程。
以下使用Future.get()方法会阻止当前线程,直到发送完成后再执行某些操作。
producer.send(record).get()
// Do some action
当使用Callback执行某些操作时,代码将在I / O线程中执行,因此它对调用线程是非阻塞的。
producer.send(record,
new Callback() {
// Do some action
}
});
虽然the docs表示它“通常”在制片人中执行:
请注意,回调通常会在生产者的I / O线程中执行,因此应该相当快,否则会延迟从其他线程发送消息。如果你想执行阻塞或计算上昂贵的回调,建议在回调体中使用你自己的Executor来并行化处理。
答案 3 :(得分:2)
我的观察基于The Kafka Producer documentation:
Future
可让您访问同步处理Future
可能无法保证确认。我的理解是Callback
将在确认后执行 Callback
可让您访问完全无阻塞异步处理。
保证发送到同一分区的记录的回调 按顺序执行。
我的另一种看法是Future
返回对象和Callback
'模式'代表两种不同的编程风格,我认为这是根本区别:
Future
表示Java的并发模型样式。Callback
表示Java的Lambda编程风格(因为Callback实际上满足功能接口的要求)您可能最终使用Future
和Callback
样式编写类似的行为,但在某些用例中,看起来样式可能比另一种更有利。
答案 4 :(得分:0)
send()是一种在Kafka Cluster上开始发布消息的方法。 send()方法是一个异步调用,它说send方法在Buffer中累积消息并立即返回。可以将它与linger.ms一起使用以批量发布消息,以提高性能。我们可以使用调用发送方法,使用Future上的get方法同步或使用带有回调的异步方法来处理异常和控制。
每种方法各有优缺点,可以根据用例确定。
异步发送(即发即忘): 我们调用如下的send方法来调用发布消息,而无需等待任何成功或错误响应。
producer.send(new ProducerRecord<String, String>("topic-name", "key", "value"));
此方案将不等待获取完整的第一条消息,而是开始发送其他消息以进行发布。如果发生异常,生产者将根据retry config参数重试,但是如果消息在重试后仍然失败,则Kafka Producer对此一无所知。在这种情况下,我们可能会发送很多消息,但是如果消息丢失很少,可以提供高吞吐量和高延迟。
同步发送 同步发送消息的简单方法是使用get()方法
RecordMetadata recMetadata = producer.send(new ProducerRecord<String, String>("topic-name", "key", "value")).get();
Producer.send返回RecordMetadata的未来,当我们调用.get()方法时,它将获得Kafka的答复。如果发生错误,我们可以捕获Error;如果成功,则可以返回RecordMetadata。 RecordMetadata包含用于记录信息的offset,partition,timestamp。它速度慢,但具有很高的可靠性,可以保证传递消息。
带回调的异步发送 我们还可以使用带有回调函数的send()方法,该方法在消息完成后返回响应。如果您想以异步方式发送消息,那就很好,这意味着您不必等待完成任务,而是要同时处理有关消息传递的错误或更新状态。
producer.send(record, new Callback(){
@Override
onComplete(RecordMetadata recodMetadata, Exception ex){...}
})
注意:请不要与异步发送呼叫的确认和重试混淆。无论是同步调用还是异步调用,Ack和重试都将应用于每个发送调用,这与如何处理返回消息和失败情况无关。例如,如果您发送异步发送仍然确认和重试规则,则该规则将被应用,但是将在独立线程上,而不会阻止其他线程发送并行记录。当消息成功完成时,如果失败和出现时间,我们将不知道唯一的挑战。