kafka偏移量offset--java

本文介绍了一个使用Apache Spark与Kafka集成的应用案例,并详细解释了如何通过Spark Kafka消费者API来配置并管理Kafka集群的消费组偏移量。文章还提供了具体的实现代码,包括如何获取和设置Kafka的开始读取偏移量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

maven

<dependency>
   <groupId>org.apache.kafka</groupId>
   <artifactId>kafka_2.10</artifactId>
   <version>0.9.0-kafka-2.0.2</version>
</dependency>
private SparkKafka kafka      = null ;

private static final String TOPIC_SOURCE = "TP_LABEL";

public SparkStoredKuduApp(String[] args){

    kafka_conf = KafkaPool.getInstance().getConfig();

    kafka_conf.setProperty("zookeeper_connect", "personas1:2181,personas2:2181,personas4:2181");
    kafka_conf.setProperty("groupid_tdx", "tpsc01"); //tpsc01
    kafka_conf.setProperty("bootstrap.servers", "personas1:9092,personas2:9092,personas4:9092");

    kafka = new SparkKafka(kafkaParams());
    kafka.setTopics(new HashSet<>(Arrays.asList(TOPIC_SOURCE)));
}

private Map<String, String> kafkaParams() {
    Map<String, String> kafkaParams = new HashMap<String, String>();
    kafkaParams.put(ConsumerConfig.GROUP_ID_CONFIG, kafka_conf.getProperty("groupid_tdx"));
    kafkaParams.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka_conf.getProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG));
    kafkaParams.put("zookeeper.connect", kafka_conf.getProperty("zookeeper_connect"));
    return kafkaParams;
}
// 获取kafka开始读取偏移量
Map<TopicAndPartition, Long> fromOffsets = kafka.getOffset();
public class SparkKafka implements Serializable {
   private static final long serialVersionUID = -7633373735487600970L;
   private Map<String, String> kafkaParams = null;
   private Set<String> topics = null;
   private KafkaCluster kafkaCluster = null;

   public SparkKafka(Map<String, String> kafkaParams) {
      this.kafkaParams = kafkaParams;
      init();
   }

   private void init() {
      scala.collection.mutable.Map<String, String> mutableKafkaParam = JavaConversions.mapAsScalaMap(kafkaParams);
      scala.collection.immutable.Map<String, String> immutableKafkaParam = mutableKafkaParam
            .toMap(new Predef.$less$colon$less<Tuple2<String, String>, Tuple2<String, String>>() {
               @Override
               public Tuple2<String, String> apply(Tuple2<String, String> v1) {
                  return v1;
               }
            });
      kafkaCluster = new KafkaCluster(immutableKafkaParam);
   }

   /**
    * 获取kafka offset
    * 
    * @return
    */
   public Map<TopicAndPartition, Long> getOffset() {
      Map<TopicAndPartition, Long> fromOffsets = new HashMap<TopicAndPartition, Long>();

      scala.collection.mutable.Set<String> mutableTopics = JavaConversions.asScalaSet(this.topics);
      scala.collection.immutable.Set<String> immutableTopics = mutableTopics.toSet();
      scala.collection.immutable.Set<TopicAndPartition> scalaTopicAndPartitionSet = kafkaCluster
            .getPartitions(immutableTopics).right().get();

      // 首次消费
      if (kafkaCluster.getConsumerOffsets(kafkaParams.get(ConsumerConfig.GROUP_ID_CONFIG), scalaTopicAndPartitionSet)
            .isLeft()) {
         scala.collection.immutable.Map<TopicAndPartition, LeaderOffset> earliestOffsetsTemp = kafkaCluster
               .getEarliestLeaderOffsets(scalaTopicAndPartitionSet).right().get();
         Set<TopicAndPartition> javaTopicAndPartitionSet = JavaConversions.setAsJavaSet(scalaTopicAndPartitionSet);
         Map<TopicAndPartition, LeaderOffset> earliestOffsets = JavaConversions.mapAsJavaMap(earliestOffsetsTemp);
         for (TopicAndPartition topicAndPartition : javaTopicAndPartitionSet) {
            LeaderOffset latestOffset = earliestOffsets.get(topicAndPartition);
            fromOffsets.put(topicAndPartition, latestOffset.offset());
         }
      } else {
         scala.collection.immutable.Map<TopicAndPartition, LeaderOffset> earliestOffsetsTemp = kafkaCluster
               .getEarliestLeaderOffsets(scalaTopicAndPartitionSet).right().get();
         scala.collection.immutable.Map<TopicAndPartition, Object> consumerOffsetsTemp = kafkaCluster
               .getConsumerOffsets(kafkaParams.get(ConsumerConfig.GROUP_ID_CONFIG), scalaTopicAndPartitionSet)
               .right().get();
         Map<TopicAndPartition, LeaderOffset> earliestOffsets = JavaConversions.mapAsJavaMap(earliestOffsetsTemp);
         Map<TopicAndPartition, Object> consumerOffsets = JavaConversions.mapAsJavaMap(consumerOffsetsTemp);
         Set<TopicAndPartition> javaTopicAndPartitionSet = JavaConversions.setAsJavaSet(scalaTopicAndPartitionSet);
         for (TopicAndPartition topicAndPartition : javaTopicAndPartitionSet) {
            LeaderOffset earliestOffset = earliestOffsets.get(topicAndPartition);
            Long offset = (Long) consumerOffsets.get(topicAndPartition);
            // 如果消费的offset小于leaderearlistOffset,有可能是kafka定时清理已删除该offset文件
            // 这时将过期的offset更新为leaderearlistOffset开始消费,避免offsetOutOfRang异常
            if (offset < earliestOffset.offset()) {
               offset = earliestOffset.offset();
            }
            fromOffsets.put(topicAndPartition, offset);
         }
      }
      return fromOffsets;
   }

   /**
    * 设置kafka offset
    * 
    * @param range
    */
   public void setOffset(HasOffsetRanges range) {
      OffsetRange[] offsets = range.offsetRanges();
      for (OffsetRange o : offsets) {
         // 封装topic.partition  offset对应关系 java Map
         TopicAndPartition topicAndPartition = new TopicAndPartition(o.topic(), o.partition());
         Map<TopicAndPartition, Object> topicAndPartitionObjectMap = new HashMap<TopicAndPartition, Object>();
         topicAndPartitionObjectMap.put(topicAndPartition, o.untilOffset());

         // 转换java map to scala immutable.map
         scala.collection.mutable.Map<TopicAndPartition, Object> map = JavaConversions
               .mapAsScalaMap(topicAndPartitionObjectMap);
         scala.collection.immutable.Map<TopicAndPartition, Object> scalatopicAndPartitionObjectMap = map.toMap(
               new Predef.$less$colon$less<Tuple2<TopicAndPartition, Object>, Tuple2<TopicAndPartition, Object>>() {
                  private static final long serialVersionUID = 1L;

                  public Tuple2<TopicAndPartition, Object> apply(Tuple2<TopicAndPartition, Object> v1) {
                     return v1;
                  }
               });

         // 更新offsetkafkaCluster
         kafkaCluster.setConsumerOffsets(kafkaParams.get(ConsumerConfig.GROUP_ID_CONFIG),
               scalatopicAndPartitionObjectMap);
      }
   }

   @SuppressWarnings("unchecked")
   public static Class<MessageAndMetadata<String, byte[]>> getMsgClass() {
      return (Class<MessageAndMetadata<String, byte[]>>) (Class<?>) MessageAndMetadata.class;
   }

   public Map<String, String> getKafkaParams() {
      return kafkaParams;
   }

   public void setKafkaParams(Map<String, String> kafkaParams) {
      this.kafkaParams = kafkaParams;
   }

   public Set<String> getTopics() {
      return topics;
   }

   public void setTopics(Set<String> topics) {
      this.topics = topics;
   }

   public KafkaCluster getKafkaCluster() {
      return kafkaCluster;
   }

   public void setKafkaCluster(KafkaCluster kafkaCluster) {
      this.kafkaCluster = kafkaCluster;
   }

}

<think>好的,用户问的是Kafka中auto.offset.reset的默认值。首先,我需要确认这个配置参数的正确名称。用户可能写成了auto-offset-reset,但实际在Kafka的配置中,使用的是点号分隔的格式,即auto.offset.reset。所以需要先纠正这一点,确保用户得到准确的信息。 接下来,回想一下Kafka消费者的配置参数。auto.offset.reset的作用是当消费者组第一次启动或者当前的偏移量不存在时(比如数据被删除),决定从哪里开始消费。常见的值有earliest、latest和none,默认值应该是latest。不过需要确认不同版本是否有变化,特别是用户可能使用的Kafka版本是否有不同的默认设置。一般来说,Kafka的文档显示默认是latest,但最好再仔细核对一下官方资料,确保没有记错。 然后考虑用户的使用场景。用户可能是在配置消费者时遇到了问题,或者刚接触Kafka,需要了解这个参数的作用和默认行为。默认值设置为latest意味着如果没有提交过偏移量,消费者会从最新的消息开始消费,而earliest则会从最早的消息开始。用户可能需要根据他们的需求调整这个配置,比如在测试时希望处理所有消息,就会设置为earliest,而在生产环境中避免重复处理旧消息,则保持latest。 此外,用户可能没有意识到这个参数的生效条件,即只有当消费者组没有初始偏移量时才会起作用。如果消费者组已经提交过偏移量,那么这个参数就不会生效。需要明确说明这一点,避免用户误解。 还要注意,如果在较旧的Kafka版本中,默认值是否有所不同。比如在0.8或更早的版本中,可能默认值不是latest?但根据现有的知识,Kafka在较新的版本中一直保持latest为默认值,所以可以确认这一点。不过最好还是建议用户查阅他们使用的版本的官方文档,以排除版本差异带来的问题。 另外,用户提到的是Kafka中的配置,可能需要区分消费者客户端的不同实现,比如Java客户端和其他语言的客户端是否一致。但通常来说,auto.offset.reset是通用的配置参数,不同客户端应该遵循相同的默认值,不过还是需要指出这一点,避免混淆。 最后,总结回答时要清晰,先给出默认值,再解释各个可选值的含义,并说明使用场景,同时提醒用户注意配置的条件和版本差异。这样用户不仅能得到答案,还能理解背后的原理,更好地应用到实际中。</think>在Kafka消费者客户端配置中,`auto.offset.reset`参数的默认值为 **latest**。以下是关键说明: ### 作用场景 当出现以下两种情况时生效: 1. 消费者组**首次启动**且没有提交过offset 2. 消费者尝试读取的offset**已过期被删除**(如超过`log.retention.hours`保留时间) ### 可选值对比 | 参数值 | 行为描述 | 典型使用场景 | |-----------|--------------------------------------------------------------------------|-----------------------------| | `latest` | 从最新的消息开始消费(跳过所有历史消息) | 生产环境,避免重复消费旧数据 | | `earliest`| 从分区最早的消息开始消费 | 数据回溯/测试全量数据消费 | | `none` | 抛出`NoOffsetForPartitionException`异常 | 需要严格offset管理的场景 | ### 配置示例(Java) ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "test-group"); props.put("auto.offset.reset", "earliest"); // 显式设置为从头消费 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); ``` ### 注意事项 1. Kafka 0.10.1.1之后版本默认值才改为`latest`,早期版本行为可能不同 2. 与`enable.auto.commit`配置配合使用时,需注意自动提交offset的间隔(默认5秒) 3. 使用`kafka-consumer-groups`命令可查看实际消费偏移量: ```bash bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group test-group ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值