我已经给出了从主题,处理器和接收器到其他主题的来源的拓扑结构
StoreBuilder storeBuilder = Stores.keyValueStoreBuilder(
Stores.persistentKeyValueStore("store"),
Serdes.String(),
Serdes.String());
Topology topology = new Topology();
topology.addSource("incoming", Serdes.String().deserializer(), Serdes.String().deserializer(), "topic");
topology.addProcessor("incoming_first", () -> new MyProcessor(), "incoming");
topology.addStateStore(storeBuilder, "incoming_first");
topology.addSink("sink", "sink", "incoming_first"),
public class MyProcessor implements Processor<String, String> {
private ProcessorContext context;
private KeyValueStore<String, String> stateStore;
@Override
public void init(ProcessorContext context) {
this.context = context;
this.stateStore = (KeyValueStore<String, String>) context.getStateStore("store");
}
@Override
public void process(String key, String value) {
stateStore.put(key, value);
....
throw new RuntimeException();
....
context.forward(); //forward to sink
}
@Override
public void close() {
}
}
我的问题是如何处理在写入状态存储后处理器中发生某些异常的情况。 Kafka是否具有某种带有状态存储回滚的错误处理机制来再次处理该消息或将其转发给错误主题?
当前,没有任何处理,我的应用程序完全死亡,需要重新启动它。 另外,如果我添加一些try-catch,则标识为ok的消息将更新状态存储,并将消息发送到changelog主题。
我需要状态存储的一些回滚机制吗?
https://issues.apache.org/jira/browse/KAFKA-7192 KIP说,如果发生异常,则不应使用EOS处理状态存储,但这仅在我的整个应用程序死亡时才有效。
谢谢!
答案 0 :(得分:1)
对于从Processor
引发的任何异常,相应的线程将始终死亡。防止这种情况的唯一方法是捕获所有异常并相应地对其进行处理(无论哪种正确的处理方式都适合您的应用程序)。
如果线程死亡,而您重新启动应用程序以恢复该线程,则是否要回滚存储取决于您的配置。默认情况下,不会回滚存储。仅当您通过设置配置参数processing.guarantees="exactly_once"
启用一次语义时,存储才会在重新启动时回滚。
如果您在Processor
代码中捕获到任何异常,并且您的业务逻辑需要回滚存储,则需要自己实现,首先从存储中获取旧值,更新存储,然后在导致异常的原因会将旧值放回存储区,以覆盖/撤消所有写入操作。