消费者消费消息时会根据之前提交的消费位移offset去kafka拉取offset之后的消息进行消费。但是一些情况下消费者开始消费时会没有消费位移,比如一个新的消费组建立的时候,或者消费组内的一个新的消费者订阅了一个新的主题,或者__consumer_offsets主题中关于这个消费组的位移信息已经过期而被删除的时候。这时消费者开始消费的消费位移就由客户端参数auto.offset.reset来决定,这个参数默认值为"latest",表示从分区末尾开始消费消息。也可以改为"earliest",表示从起始处来消费消息。也可以配置为“none”,表示找不到消费位移时直接抛出NoOffsetForPartitionException异常。
除了上述的位移重置的配置参数,消费者也可以通过seek()方法手动重置位移,此处需要注意的一个点在于consumer在通过poll方法拉取消息时,poll方法会通过调用fetcher.fetchedRecords()方法去获取消费者订阅的分区,只有这个方法返回时才能通过以下方式去获取topicPartition并且通过seek()方法重置位移。
Set<TopicPartition> topicPartition= consumer.assignment();
topicPartition.forEach(topicPartition1 -> consumer.seek(topicPartition1,offset));
poll方法带有Duration参数,可能会存在到达指定时间后,poll()方法直接返回,内部的分区分配逻辑还未实施,那么此时获取到的consumer.assignment()就是一个空集合,所以调用时需注意进行循环判断调用poll获取订阅的分区后再去调用seek方法重置位移。
消费者内的seek方法有如下几种:
//将指定分区partition的位移offset重置到offset
void seek(TopicPartition partition, long offset);
//将指定分区partition的位移offset重置到offset,并带有一些自定义的字符串元数据信息metadata
void seek(TopicPartition partition, OffsetAndMetadata offsetAndMetadata);
//将多个分区partitions消费位移offset重置到分区开头
void seekToBeginning(Collection<TopicPartition> partitions);
//将多个分区partitions消费位移offset重置到分区末尾
void seekToEnd(Collection<TopicPartition> partitions);
消费者内相关的位移方法如下:
//获取多个分区的分区开始位移
Map<TopicPartition, Long> beginningOffsets(Collection<TopicPartition> partitions);
//在指定时间内获取多个分区的分区开始位移
Map<TopicPartition, Long> beginningOffsets(Collection<TopicPartition> partitions, Duration timeout);
//获取多个分区的分区末尾位移
Map<TopicPartition, Long> endOffsets(Collection<TopicPartition> partitions);
//在指定时间内获取多个分区的分区末尾位移
Map<TopicPartition, Long> endOffsets(Collection<TopicPartition> partitions, Duration timeout);
//根据时间戳获取指定时间戳之后的消息位移
Map<TopicPartition, OffsetAndTimestamp> offsetsForTimes(Map<TopicPartition, Long> timestampsToSearch);
//指定时间内根据时间戳获取指定时间戳之后的消息位移
Map<TopicPartition, OffsetAndTimestamp> offsetsForTimes(Map<TopicPartition, Long> timestampsToSearch, Duration timeout);
通过以上方法就可以根据时间获取位移或者获取分区开始或结束的位移,并通过seek方法实现自定义位移消费。
再均衡指的是消费者上下线消费组内的消费者数量发生了变化或者消费者订阅的主题发生了变化或者主题对应的分区变化而造成的分区消息重新分配的情况。若在再均衡过程中采用了kafka的自动提交机制就可能造成再均衡前的消费者消费状态丢失的问题。比如消费者拉取并处理了一部分消息,还未来得及提交消费位移,但再均衡之后会将这个分区分配给别的消费者,就会造成已经消费的消息再次被拉取消费。这种情况也可以通过将已经处理的消息的offset暂存在程序中,在再均衡之后通过seek方法重置到之前已经处理的offset来避免。
再均衡使用seek的这一步就涉及之前讲到的再均衡监听器ConsumerRebalanceListener:
public interface ConsumerRebalanceListener {
void onPartitionsRevoked(Collection<TopicPartition> partitions);
void onPartitionsAssigned(Collection<TopicPartition> partitions);
}
ConsumerRebalanceListener中有两个方法,onPartitionsRevoked是在再均衡开始前、消费者停止读取消息之后调用,可以在此处暂存分区的消费位移或者调用commitSync同步提交消费位移。onPartitionsAssigned在重新分配分区之后、消费者开始读取消息前调用,可以在此处seek方法重置消费位移到之前暂存的位移处,如此便能避免重复消费的问题。
本文介绍了Kafka消费者在没有初始消费位移时如何通过auto.offset.reset参数设置消费起点,以及如何使用seek()方法手动重置消费位移。在讨论分区再均衡时,阐述了消费者在再均衡过程中的状态保护,如何利用ConsumerRebalanceListener避免重复消费,并通过seek方法确保消费的连续性。
632

被折叠的 条评论
为什么被折叠?



