我已经使用kafka-topic.sh
在kafka中创建了一个主题,并使用Java客户端对其进行了测试:
kafka-topics.sh \
--create \
--zookeeper localhost:2181 \
--replication-factor 1 \
--partitions 2 \
--topic my-topic
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("my-topic"), new LoggingConsumerRebalanceListener(RandomStringUtils.randomAlphanumeric(3).toLowerCase()));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(2000));
for (ConsumerRecord<String, String> record : records)
System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
Thread.sleep(500);
}
Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 10; i++) {
String key = Integer.toString(i+1);
String value = RandomStringUtils.randomAlphabetic(100);
LOGGER.info("Sending message {}", key);
producer.send(new ProducerRecord<String, String>("my-topic", key, value));
Thread.sleep(100);
}
producer.close();
生产者和使用者是我独立启动的独立代码块。
我有一个观察者,下面的代码按顺序正常工作:
但是,按照以下顺序:
生产者第一次运行时发出的消息丢失。后来,如果我停止使用者,运行生产者并运行使用者,我会收到所有消息。只有第一个使用者订阅之前产生的消息会丢失。尽管我已经在命令行中明确创建了该主题。
我在这里做错了什么?如何防止邮件丢失?
答案 0 :(得分:1)
默认情况下,使用者将读取最新的偏移量。
如果运行“生产者(1)”,然后启动使用者,它将忽略来自该生产者的消息,并等待第二个生产者的调用产生的新消息。
可以通过配置auto.offset.reset更改从最新偏移量读取的行为。
后来,如果我停止使用消费者,运行生产者并运行消费者,我会收到所有消息
之所以发生这种情况,是因为您的使用者具有固定的ConsumerGroup(配置group.id),并且默认设置auto.offset.reset不再具有任何影响,因为此组已在Kafka中注册,并且使用者将继续从主题中读取内容在哪里停了。
最后,如果要在运行第二个序列时不丢失任何消息,请设置auto.offset.reset=earliest
并定义一个新的唯一group.id
。