如何使用spring-kafka在特定的偏移量处重新发送(读取)来自给定主题和分区的旧kafka消息?

时间:2019-02-14 16:10:42

标签: apache-kafka spring-kafka

给出主题名称,分区号和偏移量,如何从该主题中读取一条记录?

在基于Sprng Boot的应用程序中,我使用Kafka导入业务数据。 导入记录被发送到 import_queue 并由一个或多个业务模块使用。即使使用者未能从记录中导入数据,也无法继续从以下记录中导入数据,但始终会确认记录。

稍后(在他/她修复了一些相关业务数据之后)用户可以决定重新发送一个或多个失败(但已确认)的导入记录。

每条记录的偏移量,分区号和主题名称都存储在我的应用程序内部的SQL数据库中。

从参考文档和一些StackOverflow问题中,我发现我必须:

  1. 设置一个容器(消费者/听众)
  2. 快退(搜索)到所需的偏移量
  3. 读取一条记录
  4. 跳过阅读剩余记录

这是从kafka主题中仅读取一个旧记录的唯一方法吗? 还是有更简单的解决方案?

解决方案

如@Gary所建议:

ConsumerRecord<byte[], byte[]> read(String topic, int partition, long offset) {
    Map<String, Object> configs = Map.of(
            "bootstrap.servers", "localhost:9092",
            "group.id", "incubator_retry",
            "max.poll.records", 1);
    DefaultKafkaConsumerFactory<byte[], byte[]> consumerFactory = new DefaultKafkaConsumerFactory<>(
            configs, new ByteArrayDeserializer(), new ByteArrayDeserializer());

    try (Consumer<byte[], byte[]> consumer = consumerFactory.createConsumer()) {
        TopicPartition topicPartition = new TopicPartition(topic, partition);
        consumer.assign(List.of(topicPartition));
        consumer.seek(topicPartition, offset);
        ConsumerRecords<byte[], byte[]> consumerRecords = consumer.poll(Duration.ofMillis(5000));
        if (consumerRecords.isEmpty()) {
            throw new RuntimeException(String.format("Timeout polling from topic %s partition %d at offset %d",
                    topicPartition.topic(), topicPartition.partition(), offset));
        }
        return consumerRecords.iterator().next();
    }
}

1 个答案:

答案 0 :(得分:1)

有一个更简单的解决方案。

  • 使用DefaultConsumerFactory创建一个KafkaConsumer(或简单地创建一个)
  • 使用其他group.id
  • max.poll.records属性设置为1
  • consumer.assign(...)所需的主题/分区
  • seek(...)到所需的偏移量
  • poll(...)直到获得记录
  • close()消费者

如果您正在使用任何消息转换(除了Kafka解串器),则必须手动调用该转换器。