如何在多次呼叫消费者时重置Kafka消费者偏移量

时间:2018-05-08 07:45:56

标签: java apache-kafka

我试图在调用消费者时重置消费者offset,这样当我多次呼叫消费者时,它仍然可以读取生产者发送的记录。我设置props.put("auto.offset.reset","earliest");并呼叫consumer.seekToBeginning(consumer.assignment());,但是当我第二次呼叫消费者时,它将不会收到任何记录。我该如何解决这个问题?

   public ConsumerRecords<String, byte[]> consumer(){
    Properties props = new Properties();
    props.put("bootstrap.servers", "localhost:9092");
    props.put("group.id", "test");
    //props.put("group.id", String.valueOf(System.currentTimeMillis()));
    props.put("auto.offset.reset","earliest");
    props.put("enable.auto.commit", "true");
    props.put("auto.commit.interval.ms", "1000");
    props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    props.put("value.deserializer", "org.apache.kafka.common.serialization.ByteArrayDeserializer");
    KafkaConsumer<String, byte[]> consumer = new KafkaConsumer<>(props);
    consumer.subscribe(Collections.singletonList("topiccc"));
    ConsumerRecords<String, byte[]> records = consumer.poll(100);
    consumer.seekToBeginning(consumer.assignment());
   /* List<byte[]> videoContents = new ArrayList<byte[]>();
    for (ConsumerRecord<String, byte[]> record : records) {
        System.out.printf("offset = %d, key = %s, value = %s\n", record.offset(), record.key(), record.value());
        videoContents.add(record.value());
    }*/

    return records;
} 

public String producer(@RequestParam("message") String message) {
    Map<String, Object> props = new HashMap<>();
    // list of host:port pairs used for establishing the initial connections to the Kakfa cluster
    props.put("bootstrap.servers", "localhost:9092");
    props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    props.put("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer");
    Producer<String, byte[]> producer = new KafkaProducer<>(props);
    Path path = Paths.get("C:/Programming Files/video-2012-07-05-02-29-27.mp4");
    ProducerRecord<String, byte[]> record = null;
    try {

        record = new ProducerRecord<>("topiccc", "keyyyyy"
                , Files.readAllBytes(path));

    } catch (IOException e) {
        e.printStackTrace();
    }
    producer.send(record);
    producer.close();
    //kafkaSender.send(record);

    return "Message sent to the Kafka Topic java_in_use_topic Successfully";
}

4 个答案:

答案 0 :(得分:0)

我通常使用不同的group.id创建一个新的使用者来再次读取记录。 所以这样做:

props.put("group.id", Instant.now().getEpochSecond());

答案 1 :(得分:0)

有一种解决方法(不是生产解决方案),每次使用时都会更改group.id配置值。在许多情况下,将auto.offset.reset设置为earliest是不够的。

答案 2 :(得分:0)

根据 Kafka Java 代码,AUTO_OFFSET_RESET_CONFIG 上的 documentation 说明如下:

<块引用>

当Kafka中没有初始偏移量或者服务器上不再存在当前偏移量(例如因为该数据已被删除)时该怎么办:

  • 最早:自动重置偏移量到最早的偏移量
  • latest:自动将偏移量重置为最新的偏移量
  • none:如果没有找到消费者组的先前偏移量,则向消费者抛出异常
  • < li>其他任何事情:向消费者抛出异常。

    这可以在 GitHub 中找到: https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerConfig.java

    我们从他们的评论中可以看出,该设置仅在偏移量不在服务器上时使用。在问题中,偏移量是从服务器检索的,这就是为什么偏移量没有重置到开头而是停留在最后一个偏移量处,从而看起来没有更多记录。

    您需要在服务器端明确重置偏移量才能按照问题中的要求解决此问题。

    这是另一个描述如何做到这一点的答案。 https://stackoverflow.com/a/54492802/231860

    这是一段代码,允许我重置偏移量。注意:如果调用 subscribe 方法,则不能调用 seekToBeginning。如果我自己使用分配方法分配分区,我只能让它工作。可惜。

    // Create the consumer:
    final Consumer<String, DataRecord> consumer = new KafkaConsumer<>(props);
    
    // Get the partitions that exist for this topic:
    List<PartitionInfo> partitions = consumer.partitionsFor(topic);
    
    // Get the topic partition info for these partitions:
    List<TopicPartition> topicPartitions = partitions.stream().map(info -> new TopicPartition(info.topic(), info.partition())).collect(Collectors.toList());
    
    // Assign all the partitions to the topic so that we can seek to the beginning:
    // NOTE: We can't use subscribe if we use assign, but we can't seek to the beginning if we use subscribe.
    consumer.assign(topicPartitions);
    
    // Make sure we seek to the beginning of the partitions:
    consumer.seekToBeginning(topicPartitions);
    

    是的,实现一个看似基本的用例似乎极其复杂。这可能表明整个 kafka 世界似乎只想读取一次流。

    答案 3 :(得分:0)

    当您希望消费者多次使用一条消息时,理想的方法是创建具有不同消费者组的消费者,以便可以使用相同的消息。

    但是如果你想让同一个消费者多次消费同一个消息,那么你可以使用 commit 和 offset 您将 auto.commit 设置得非常高或禁用它并按照您的逻辑进行提交

    您可以参考此了解更多详情https://kafka.apache.org/10/javadoc/org/apache/kafka/clients/consumer/KafkaConsumer.html 此 javadoc 提供了有关如何手动管理偏移量的详细信息