kafka消费者自动提交如何工作?

时间:2017-10-03 14:01:43

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

我正在阅读this one

  

自动提交提交偏移的最简单方法是允许   消费者为你做的。如果配置enable.auto.commit = true,   然后消费者每五秒钟提交一次最大的偏移量   您的客户从poll()收到。五秒钟的间隔是   默认值并通过设置auto.commit.interval.ms来控制。只是   与消费者中的其他所有内容一样,自动提交也会受到驱动   通过民意调查循环。每当您进行轮询时,消费者都会检查是否是时间   提交,如果是,它将提交它返回的偏移量   最后一次民意调查。

也许发现我的英语不好但我不完全理解这个描述。

假设我使用默认间隔的自动提交 - 5秒,并且每7秒轮询一次。在这种情况下,提交将每5秒或每7秒发生一次?

如果民意调查每3秒发生一次,你能澄清一下行为吗?是每5秒还是每6秒发生一次? 我看过this one

  

自动提交:您可以将auto.commit设置为true并设置   auto.commit.interval.ms属性,其值以毫秒为单位。一旦   你已经启用了这个,Kafka消费者将承诺抵消   收到最后一条消息以响应其poll()调用。 poll()调用   在后台以set auto.commit.interval.ms。

发布

这与答案相矛盾。

你能否详细解释一下这些东西。

假设我有这样的例子:

  

0秒 - 投票
  4秒 - 投票
  8秒 - 民意调查

什么时候会提交偏移以及何时提交?

4 个答案:

答案 0 :(得分:9)

每次轮询都会调用自动提交检查,并检查经过的时间是否大于配置的时间。如果是,则提交偏移量。

如果提交间隔为5秒且轮询在7秒内发生,则提交将在7秒后发生。

答案 1 :(得分:5)

它将尝试在轮询完成后自动提交ASAP。您可以查看使用者协调器的源代码,该代码具有在类级别定义的一组本地字段,以了解是否启用了自动提交,间隔是什么,以及执行自动提交的下一个截止日期是什么。

https://github.com/apache/kafka/blob/10cd98cc894b88c5d1e24fc54c66361ad9914df2/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerCoordinator.java#L625

进行调查以进行存储https://github.com/apache/kafka/blob/10cd98cc894b88c5d1e24fc54c66361ad9914df2/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ConsumerCoordinator.java#L279

的其中一个投票地点

例如,每7秒执行一次轮询,并且自动提交设置为5:

  

0 - 民意调查,+将截止日期设为第5秒

     

7 - 因截止日期而投票+提交,更新截止日期为7 + 5 = 12

     

14 - 由于截止日期而投票+提交,更新截止日期为12 + 5 = 17

但是,如果轮询设置为每3秒,并且自动提交设置为5:

  

0 - 民意调查,+将截止日期设为第5秒

     

3 - 民意调查,没有提交

     

6 - 由于截止日期而投票+提交,更新截止日期为6 + 5 = 11

答案 2 :(得分:0)

看看下面的配置,它们为 Kafka 消费者调优提供了另一个视角: 对于来自生产者的 30 条记录,如果消费者在 20 秒前崩溃,那么整个 30 条记录将被消费者再次读取,因为 max-poll-interval 和 auto-commit-interval 都设置为 20 秒

 auto-commit-interval: 20000
      auto-offset-reset: latest
      max-poll-records: 10
      max-poll-interval-ms: 20000

但是对于下面的配置,自动提交每 2 秒发生一次并且消费者在任何时间点崩溃 > 2 秒,那么那些已经提交给 Kafka 生产者的记录将不会被消费者再次接收。

 auto-commit-interval: 2000
      auto-offset-reset: latest
      max-poll-records: 10
      max-poll-interval-ms: 20000

此外,auto-commit-interval 总是优先于 max-poll-interval。如果自动提交由于某种奇怪的原因没有发生,那么在 20 秒的 max-poll-interval 过去后,Kafka 代理会得出结论,消费者已关闭。

答案 3 :(得分:0)

这里有一个简单的代码来测试它是如何工作的。

文档 -> https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html

public class KafkaTest {
    
    public static final String KAFKA_TOPIC_NAME = "kafka-xx-test-topic";
    public static final String CONSUMER_GROUP_ID = "test-consumer-xx";
    public static final String BOOTSTRAP_SERVERS = "localhost:9092";

    public static void main(String[] args) {
        final KafkaProducer<Object, Object> kafkaProducer = new KafkaProducer<>(getProps());
        for (int i = 0; i < 1000; i++) {
            kafkaProducer.send(new ProducerRecord<>(KAFKA_TOPIC_NAME, "Data_" + i));
        }
        final Consumer<Long, String> consumer = new KafkaConsumer<>(getProps());
        consumer.subscribe(Collections.singletonList(KAFKA_TOPIC_NAME));
        TopicPartition actualTopicPartition = new TopicPartition(KAFKA_TOPIC_NAME, 0);
        while (true) {
            final ConsumerRecords<Long, String> consumerRecords = consumer.poll(Duration.ofSeconds(60));
            consumerRecords.forEach(record -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(200);
                } catch (InterruptedException e) {
                }
            });
            final long committedOffset = consumer.committed(Collections.singleton(actualTopicPartition)).get(actualTopicPartition).offset();
            final long consumerCurrentOffset = consumer.position(actualTopicPartition);
            System.out.println("Poll finish.. consumer-offset: " + consumerCurrentOffset + " - committed-offset: " + committedOffset + " " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
        }
    }

    private static Map<String, Object> getProps() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, CONSUMER_GROUP_ID);
        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest"); //  Default: latest
        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); // Default: true
        props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 10); // Default: 500
        props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 5000); // Default: 5000
        return props;
    }
}
  • 每 2 秒轮询一次
  • 每 5 秒自动提交一次

输出如下

Poll finish.. consumer-offset: 1010 - committed-offset: 1000 17:07:05
Poll finish.. consumer-offset: 1020 - committed-offset: 1000 17:07:07
Poll finish.. consumer-offset: 1030 - committed-offset: 1000 17:07:09
Poll finish.. consumer-offset: 1040 - committed-offset: 1030 17:07:11 -> commit when poll finish because of elapsed time(6 sec) > commit interval(5 sec)
Poll finish.. consumer-offset: 1050 - committed-offset: 1030 17:07:13
Poll finish.. consumer-offset: 1060 - committed-offset: 1030 17:07:15
Poll finish.. consumer-offset: 1070 - committed-offset: 1060 17:07:17 -> auto commit 
Poll finish.. consumer-offset: 1080 - committed-offset: 1060 17:07:19
Poll finish.. consumer-offset: 1090 - committed-offset: 1060 17:07:21
Poll finish.. consumer-offset: 1100 - committed-offset: 1090 17:07:23 -> auto commit