我很难在Kafka主题的消费者中找到处理异常的简单模式。 场景如下:在消费者中我称之为外部服务。如果服务不可用,我想重试几次,然后停止消费。
最简单的模式似乎是一种阻塞同步的处理方式,在java中是这样的:
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
boolean processed=false;
int count=0;
while (!processed) {
try {
callService(..);
} catch (Exception e) {
if (count++ < 3) {
Thread.sleep(5000);
continue;
} else throw new RuntimeException();
}
}
}
但是,我觉得必须有一个更简单的方法(不使用第三方库),以及避免阻塞线程的方法。
似乎我们希望拥有一个常见的东西,但我找不到这个模式的简单示例。
答案 0 :(得分:1)
Kafka没有开箱即用的重审机制。有了使用RabbitMQ的经验,MQ提供了重试交换。这些交换在RabbitMQ中称为Dead-Letter-Exchanges
。
https://www.rabbitmq.com/dlx.html
对于kafka,您可以应用相同的模式。
在消息处理失败时,我们可以将消息的副本发布到另一个主题并等待下一条消息。我们将新主题称为“retry_topic
”。 'retry_topic
'的消费者将从Kafka接收消息,然后在开始消息处理之前等待一些预定义的时间,例如一小时。通过这种方式,我们可以推迟下一次消息处理尝试,而不会对'main_topic'消费者产生任何影响。如果'retry_topic'消费者中的处理失败,我们只需放弃并将消息存储在'failed_topic'中,以便进一步手动处理此问题。 'main_topic'消费者代码可能如下所示:
在失败/异常时将消息推送到retry_topic
void consumeMainTopicWithPostponedRetry() {
while (true) {
Message message = takeNextMessage("main_topic");
try {
process(message);
} catch (Exception ex) {
publishTo("retry_topic");
LOGGER.warn("Message processing failure. Will try once again in the future.", ex);
}
}
}
重试主题的消费者
void consumeRetryTopic() {
while (true) {
Message message = takeNextMessage("retry_topic");
try {
process(message);
waitSomeLongerTime();
} catch (Exception ex) {
publishTo("failed_topic");
LOGGER.warn("Message processing failure. Will skip it.", ex);
}
}
}
上述策略和示例摘自以下链接。整个功劳归功于博文的所有者。 https://blog.pragmatists.com/retrying-consumer-architecture-in-the-apache-kafka-939ac4cb851a
通过阅读整篇博文,可以理解上面做的非阻塞方式。希望这会有所帮助。