数据库失败时重试kafka消息消耗

时间:2018-03-21 03:50:43

标签: java apache-kafka kafka-consumer-api

我对卡夫卡比较新。

我们处理来自kafka的消息并将它们持久化到数据库。如果将它们持久化到数据库时出现故障,则不会提交消息。

我的问题是: 我们想知道如何重新使用未提交的消息?

我尝试了一些方法。

  1. 重新启动消费者。它有效,但依赖于重新启动。
  2. 抓住应用程序异常并跳过kafka提交。将消息存储到RAM中,然后重试。
  3. 在这种情况下最佳做法是什么?提前致谢。

2 个答案:

答案 0 :(得分:0)

如果您使用spring-Kafka项目,则可以使用ContainerStoppingErrorHandler这将导致错误地停止容器。下面是示例KafkaListener方法,该方法将在DataAccessException上重试并在将耗尽的传递错误退回到下面的Config类中定义的错误处理程序之后

@KafkaListener(topics = ("${spring.kafka.consumer.topic}"), containerFactory = "kafkaManualAckListenerContainerFactory")
@Retryable(include = DataAccessException.class, backoff = @Backoff(delay = 20000, multiplier = 3))
public void onMessage(List<ConsumerRecord<String, String>> recordList,
                      Acknowledgment acknowledgment, Consumer<?, ?> consumer) throws DataAccessException {

    try {
        kafkaSinkController.saveToDb(recordList);
        acknowledgment.acknowledge();
        LOGGER.info("Message Saved  DB");
    } catch (Exception e) {
        LOGGER.error("Other than db exception ", e)
    }
}

配置bean

@Bean
KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, String>>
kafkaManualAckListenerContainerFactory() {
    ConcurrentKafkaListenerContainerFactory<String, String> factory =
            new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory(new DefaultKafkaConsumerFactory<String, String>(consumerConfig));
    factory.setConcurrency(concurrentConsumerCount);
    factory.getContainerProperties().setAckMode(AckMode.MANUAL_IMMEDIATE);
    factory.getContainerProperties().setBatchErrorHandler(new ContainerStoppingBatchErrorHandler()); 
//It will stop container and thus consumer will stop listening
    factory.setBatchListener(true);
    return factory;
}

当你想开始重新消费消息时,可以使用KafkaListenerEndpointRegistry启动容器,下面的示例方法用于引用,一旦数据库启动,可以通过以此方法的端点公开的方式以编程方式调用。

@Autowired
KafkaListenerEndpointRegistry registry;

public void startContainer() {
    try {
        registry.start(); 
    } catch (Exception ex) {
        //Todo
    }
}

以上样本依赖于所有弹簧组件,但如果没有spring-kafka项目,也可以实现相同的目标。

答案 1 :(得分:0)

捕获异常并将消息发布到另一个Kafka重试主题,该主题将由另一个使用者单独处理。