Java 多次呼叫消费者时如何重置卡夫卡消费者偏移量
无论何时调用消费者,我都会尝试重置消费者Java 多次呼叫消费者时如何重置卡夫卡消费者偏移量,java,apache-kafka,Java,Apache Kafka,无论何时调用消费者,我都会尝试重置消费者偏移量,这样当我多次调用消费者时,它仍然可以读取生产者发送的记录。我正在设置props.put(“auto.offset.reset”,“最早”)并调用消费者。请参见tobegining(consumer.assignment())但当我第二次呼叫消费者时,它将不会收到任何记录。我怎样才能解决这个问题 public ConsumerRecords<String, byte[]> consumer(){ Properties pro
偏移量,这样当我多次调用消费者时,它仍然可以读取生产者发送的记录。我正在设置props.put(“auto.offset.reset”,“最早”)代码>并调用消费者。请参见tobegining(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";
}
公共消费者记录消费者(){
Properties props=新属性();
put(“bootstrap.servers”,“localhost:9092”);
props.put(“group.id”、“test”);
//put(“group.id”,String.valueOf(System.currentTimeMillis());
道具放置(“自动偏移重置”、“最早”);
props.put(“enable.auto.commit”、“true”);
props.put(“auto.commit.interval.ms”,“1000”);
put(“key.deserializer”、“org.apache.kafka.common.serialization.StringDeserializer”);
put(“value.deserializer”、“org.apache.kafka.common.serialization.ByteArraydSerializer”);
卡夫卡消费者=新卡夫卡消费者(道具);
consumer.subscribe(Collections.singletonList(“topiccc”);
ConsumerRecords记录=consumer.poll(100);
consumer.seektobegining(consumer.assignment());
/*List videoContents=new ArrayList();
对于(消费者记录:记录){
System.out.printf(“偏移量=%d,键=%s,值=%s\n”,record.offset(),record.key(),record.value());
videoContents.add(record.value());
}*/
退货记录;
}
公共字符串生成器(@RequestParam(“message”)字符串消息){
Map props=newhashmap();
//主机列表:用于建立到Kakfa集群的初始连接的端口对
put(“bootstrap.servers”,“localhost:9092”);
put(“key.serializer”、“org.apache.kafka.common.serialization.StringSerializer”);
put(“value.serializer”、“org.apache.kafka.common.serialization.ByteArraySerializer”);
制作人=新卡夫卡制作人(道具);
Path Path=Path.get(“C:/Programming Files/video-2012-07-05-02-29-27.mp4”);
ProducerRecord记录=null;
试一试{
记录=新产品记录(“topiccc”、“keyyyyy”
,Files.readAllBytes(路径));
}捕获(IOE异常){
e、 printStackTrace();
}
制作人。发送(记录);
producer.close();
//卡夫卡森德。发送(记录);
返回“发送到卡夫卡主题java_in_use_主题的消息成功”;
}
我通常使用不同的group.id创建一个新的消费者,以便再次读取记录。
那么就这样做吧:
props.put("group.id", Instant.now().getEpochSecond());
有一种解决方法(虽然不是生产解决方案),即每次消费时更改group.id
配置值。在许多情况下,将auto.offset.reset
设置为earlime
是不够的。根据卡夫卡Java代码,on auto_offset\u reset\u配置说明如下:
如果Kafka中没有初始偏移量,或者服务器上不再存在当前偏移量(例如,因为该数据已被删除),该怎么办:最早:自动将偏移量重置为最早偏移量 最新:自动将偏移量重置为最新偏移量 无:如果未找到消费者组的以前偏移量,则向消费者抛出异常 其他:向消费者抛出异常。
这可以在GitHub中找到:
我们可以从他们的评论中看到,该设置仅在偏移量不在服务器上时使用。在这个问题中,偏移量是从服务器检索的,这就是为什么偏移量不会重置为起始偏移量,而是保持在最后一个偏移量,从而使它看起来没有更多的记录
您需要在服务器端显式重置偏移量,以按照问题中的要求修复此问题
下面是另一个答案,描述了如何做到这一点。
这是一段允许我重置偏移量的代码。注意:如果调用subscribe方法,则不能调用seektobegining。只有我自己使用assign方法分配分区,我才能让它工作。可怜
// 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);
//创建消费者:
最终消费者=新卡夫卡消费者(道具);
//获取此主题存在的分区:
List partitions=consumer.partitions(主题);
//获取这些分区的主题分区信息:
List topicPartitions=partitions.stream().map(info->newtopicpartition(info.topic(),info.partition()).collect(Collectors.toList());
//将所有分区分配给主题,以便我们可以从头开始:
//注意:如果使用assign,我们不能使用subscribe,但是如果使用subscribe,我们不能从头开始。
consumer.assign(主题分区);
//确保我们搜索到分区的开头:
消费者。参见主题分类;
是的,实现一个看似基本的用例似乎非常复杂。这可能表明整个卡夫卡世界似乎只想读一次流。当您希望一条消息被消费者多次消费时,理想的方法是创建具有不同消费群体的消费者,以便可以消费相同的消息
但是,如果希望同一消费者多次使用同一消息,则可以使用commit和offset
您可以将auto.commit设置得非常高,或者禁用它,然后按照您的逻辑进行提交
有关更多详细信息,请参阅此
此javadoc提供了有关如何手动管理偏移量的详细信息如果您尝试手动执行此操作,是否有效?例如,kafka-consumer-groups.bat——引导服务器kafka主机:9092——分组我的组——重置偏移量——到最早——所有主题——执行
我需要在程序中执行,但在线程“main”中出现异常org.apache.kafka.common.config.ConfigException:bootstrap.servers中没有提供可解析的引导URL,尽管我已将其设置为“localhost:9092”,但您需要发布完整代码。@giorgosmyriantous我添加了