已经经历了多个帖子,但是大多数都是相关的处理错误消息,而不是关于处理它们时的异常处理。
我想知道如何处理流应用程序收到的消息,并且在处理消息时出现异常?该异常可能是由于多种原因造成的,例如网络故障,RuntimeException等,
setUncaughtExceptionHandler
?或者,还有更好的方法? 提前谢谢!
答案 0 :(得分:5)
这取决于您要如何处理生产者方面的异常。
如果将对生产者抛出异常(例如,由于网络故障或kafka代理已死亡),则默认情况下流将死亡。在kafka-streams 1.1.0版中,您可以通过实现ProductionExceptionHandler
来覆盖默认行为,如下所示:
public class CustomProductionExceptionHandler implements ProductionExceptionHandler {
@Override
public ProductionExceptionHandlerResponse handle(final ProducerRecord<byte[], byte[]> record,
final Exception exception) {
log.error("Kafka message marked as processed although it failed. Message: [{}], destination topic: [{}]", new String(record.value()), record.topic(), exception);
return ProductionExceptionHandlerResponse.CONTINUE;
}
@Override
public void configure(final Map<String, ?> configs) {
}
}
从句柄方法,如果您不希望流因异常而死,则可以返回CONTINUE
,如果希望流停止,则返回FAIL
(FAIL是默认值之一)。
并且您需要在流配置中指定此类:
default.production.exception.handler=com.example.CustomProductionExceptionHandler
还请注意,ProductionExceptionHandler
仅处理生产者上的异常,并且在使用流方法mapValues(..)
,filter(..)
,branch(..)
等处理消息时不会处理异常,您需要使用try / catch块包装这些方法逻辑(将所有方法逻辑放入try块中,以确保您将处理所有例外情况):
.filter((key, value) -> { try {..} catch (Exception e) {..} })
据我所知,我们不需要在消费者端显式处理异常,因为kafka流稍后会自动重试(因为偏移量直到消息被使用和处理后才会更改);例如如果kafka代理在一段时间内无法访问,则会从kafka流中获取异常,并且当损坏时,kafka流将消耗所有消息。因此在这种情况下,我们将只是延迟而没有损坏/丢失。
使用setUncaughtExceptionHandler
,您将无法像使用ProductionExceptionHandler
那样更改默认行为,因为它只能记录错误或将消息发送到失败主题。
答案 1 :(得分:2)
要在消费者端处理异常,
1)您可以使用以下属性在生产者中添加默认异常处理程序。 “ default.deserialization.exception.handler” =“ org.apache.kafka.streams.errors.LogAndContinueExceptionHandler”;
基本上apache提供了三个异常处理程序类,
1)LogAndContiuneExceptionHandler,您可以将其用作 props.put(StreamsConfig.DEFAULT_DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG, LogAndContinueExceptionHandler.class);
2)LogAndFailExceptionHandler props.put(StreamsConfig.DEFAULT_DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG, LogAndFailExceptionHandler.class);
3)LogAndSkipOnInvalidTimestamp props.put(StreamsConfig.DEFAULT_DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG, LogAndSkipOnInvalidTimestamp.class);
对于自定义异常处理,
1)您可以实现DeserializationExceptionHandler接口并覆盖handle()方法。
2)或者您可以扩展上述类。
答案 2 :(得分:1)
setUncaughtExceptionHandler 无助于处理异常,它由于某些未捕获的异常而在流终止后起作用。
Kafka提供了几种处理异常的方法。一个简单的 try-catch {} 将有助于捕获处理器代码中的异常,但是kafka反序列化异常(可能是由于数据问题引起的)和生产异常(与代理进行通信时发生)需要 DeserializationExceptionHandler < / strong>和 ProductionExceptionHandler 。默认情况下,如果遇到任何上述情况,kafka应用程序都会失败。
您可以在此post
上找到答案 3 :(得分:0)
在 Spring cloud stream 中,您可以使用以下方法配置自定义反序列化处理程序:
spring.cloud.stream.kafka.streams.binder.configuration.default.deserialization.exception.handler=your-package-name.CustomLogAndContinueExceptionHandler
CustomLogAndContinueExceptionHandler 扩展 LogAndContinueExceptionHandler 或实现 DeserializationExceptionHandler
CustomLogAndContinueExceptionHandler DeserializationHandlerResponse.CONTINUE 或 FAIL 取决于您的用例
@Slf4j
public class CustomLogAndContinueExceptionHandler extends LogAndContinueExceptionHandler {
@Override
public DeserializationHandlerResponse handle(ProcessorContext context, ConsumerRecord<byte[], byte[]> record,
Exception exception) {
.... some business logic here ....
log.error("Message failed: taskId: {}, topic: {}, partition: {}, offset: {}, , detailerror : {}",
context.taskId(), record.topic(), record.partition(), record.offset(), exception.getMessage());
return DeserializationHandlerResponse.CONTINUE;
}
}