KafkaConsuner 指定开始消费的位置

KafkaConsumer 指定消费位置的基础

一个 Topic 对应着磁盘上的几个重要的文件:

  • .log:数据文件,存储了该 topic 中的所有消息。
  • .index:索引文件,对数据文件中的消息进行索引。关键就是可以按照 offset 来索引
  • .timeindex:时间索引文件,类似于索引文件,但按照消息的时间戳进行索引。它保存着 timestamp-offset 的关系,所以可以使用时间戳找到对应的 offset ,然后再找到对应的 offset 位置,这样就能找到对应的文件开始的位置了。
  • leader-epoch-checkpoint:该文件的职责是存储leader对于topic的进度,以便在leader重启时可以重新定位到上一次成功提交的offset位置。

在我们探讨的功能中,index和timeindex两个文件扮演着关键角色,它们与消费者开始消费的位置密切相关。这是我们今天要讲解的核心基础,没有这两个文件,我们无法进行后续的操作。

具体的做法

方法名 用法 业务意义
subscribe() consumer.subscribe(Arrays.asList(“topic1”, “topic2”)); 订阅一个或多个主题,按照策略指定当前消费者实例消费那个分区的数据
assign() TopicPartition partition0 = new TopicPartition(“test”, 0);
consumer.assign(Arrays.asList(partition0));
指定分配的TopicPartition,手工指定当前消费者实例消费那个分区的数据
assignment() Set partitions = consumer.assignment(); 获取当前已分配的TopicPartition列表
beginningOffsets() Map beginningOffsets = consumer.beginningOffsets(Arrays.asList(partition0)); 获取指定TopicPartition的起始偏移量信息

说明:

  • subscribe()assign() 两个方法的使用是互斥的,只能使用其中之一。
  • assignment() 方法只能在 consumer 已经订阅主题或手动分配分区之后使用,否则返回空列表。

在执行subscribe()assign() 之后,assignment() 才能获取到偏移的位置,否返回一个 size() = 0 的 map。更加让人不能接收的是执行subscribe() 之后,仍然assignment() 不能获取 TopicPartition 信息。需要在执行了 poll() 方法之后才行。这就比较扯了。我本来想指定一个开始位置,但是还没有指定位置呢?先让我消费出来点数据,这不是多余吗?

在 FlinkKafkaConsumer 类中,使用了 assign() + seek 的方式,指定了消费者的消费位置,这样以来, __consumer_offsets 就用了,FlinkKafkaConsumer 不是从 checkpoint 消费,就能是手工指定的位置消费了。

关键代码


``````java 
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.TopicPartition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

public class KafkaConsumerAt {
    private static Logger logger = LoggerFactory.getLogger(KafkaConsumerAt.class);

    public static void main(String[] args) throws InterruptedException {
        Properties p = new Properties();
        p.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG , "your.kafka.address:9092");
        p.setProperty(ConsumerConfig.GROUP_ID_CONFIG , "test-text-001");
        p.setProperty(ConsumerConfig.MAX_POLL_RECORDS_CONFIG,"5");
        p.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG , "org.apache.kafka.common.serialization.StringDeserializer");
        p.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG , "org.apache.kafka.common.serialization.StringDeserializer");
        KafkaConsumer<String,String> consumer = new KafkaConsumer<String, String>(p);

        String topic = "test_create_timestamp" ;

        Map<TopicPartition, Long> tpl = new HashMap<>();
        List<PartitionInfo> partitionInfos = consumer.partitionsFor(topic);
        TopicPartition topicPartition = null ;
        for (PartitionInfo partitionInfo : partitionInfos) {
            topicPartition =new TopicPartition(partitionInfo.topic() , partitionInfo.partition());
            tpl.put(topicPartition , 0L);
        }

        List<TopicPartition> topicPartitions = Collections.singletonList(topicPartition);
        consumer.assign(topicPartitions);
        tpl.forEach((key,value)->{
            consumer.seek(key , value);
        });

        ConsumerRecords<String,String> records = consumer.poll(Duration.ofSeconds(1L));

        for (ConsumerRecord<String, String> record : records) {
            logger.info("key:{} value:{} offset:{} timestamp:{} timestampType:{}", record.key(), record.value(), record.offset(), record.timestamp(), record.timestampType());
        }
        consumer.close();
    }
}
 

你可能感兴趣的:(kafka,java,开发语言,kafka)