如果我连续几次向Kafka集群发布消息(使用new Producer API),我会从生产者那里获得每条消息的Future
。
现在,假设我已经将我的生产者配置为max.in.flight.requests.per.connection = 1
和retries > 0
,我可以等到最后的未来,并确保之前的所有生产商都已交付(并按顺序)?或者我需要等待所有期货?
在代码中,我可以执行此操作:
Producer<String, String> producer = new KafkaProducer<>(myConfig);
Future<?> f = null;
for(MessageType message : messages){
f = producer.send(new ProducerRecord<String,String>("myTopic", message.getKey(), message.getValue());
}
try {
f.get();
} catch(ExecutionException e) {
//handle exception
}
而不是:
Producer<String, String> producer = new KafkaProducer<>(myConfig);
List<Future<?>> futureList = new ArrayList<>();
for(MessageType message : messages){
futureList.add(producer.send(new ProducerRecord<String,String>("myTopic", message.getKey(), message.getValue()));
}
try {
for(Future<?> f : futureList) {
f.get();
}
} catch(ExecutionException e) {
//handle exception
}
并确保如果此处没有捕获任何内容(来自第一个代码段):
try {
f.get();
} catch(ExecutionException e) {
然后然后我的所有消息都按顺序存储在集群中(无论生产者是否在引擎盖下执行了任何重试),如果出现问题,那么即使它出现了异常第一次遇到这个问题不是最后的未来(我在等待)?
是否有更多奇怪的角落需要注意?
答案 0 :(得分:1)
您可以执行此操作,但仅如果您a)将重试设置为无限(或实际上无限),并且b)如果您遇到不可重试的异常,则可以丢弃数据。
为了解释一下,Kafka有两类例外。可逆异常是指如果再次运行它可能会成功的失败。例如,NotEnoughReplicasException
表示副本数量少于您的要求,因此请求被拒绝。但是如果一个失败的经纪人重新上线,那么你可能有足够的副本,恢复状态良好,如果再次发送请求,请求就会成功。相反,SerializationException
是不可重复的,因为我们没有理由相信如果你再次尝试序列化,结果会有所不同。
生产者重试仅适用于您遇到不可重试的异常的点。因此,如果您从未尝试过任何这些,请使用无限重试,并使用您提到的其他设置,一旦最终的未来得到解决,订购和成功交付将得到保证。但是,由于您可能会遇到不可重试的异常,因此处理每个未来(或回调)肯定要好得多,并确保在请求失败时至少记录一些内容。
答案 1 :(得分:1)
除了Ewen所说的,你还可以在循环中发送完所有消息后拨打flush()。此通话将一直阻止,直到所有期货都已完成,因此在此之后您可以检查期货是否有任何例外情况。你需要坚持所有的期货才能做到这一点。
另一种方法是对您的发送使用回调并存储任何返回的异常,如下所示。再次使用flush确保在检查异常之前已完成所有发送。
Producer<String, String> producer = new KafkaProducer<>(myConfig);
final ArrayList<Exception> exceptionList = new ArrayList<>();
for(MessageType message : messages){
producer.send(new ProducerRecord<String, String>("myTopic", message.getKey(), message.getValue()), new Callback() {
@Override
public void onCompletion(RecordMetadata metadata, Exception exception) {
if (exception != null) {
exceptionList.add(exception);
}
}
});
}
producer.flush();
if (!exceptionList.isEmpty()) {
// do stuff
}