我对Apache Kafka有两个问题。
Thread.sleep(1000)
(在消耗方法中)。发现
在Zookeeper和kafka服务关闭后,消费者继续在控制台上编写消息。
期望
在饲养员和卡夫卡长大后,消费者应停止使用消息,并从最后一条消息的索引+ 1重新开始。
问题
如何使使用者从上次使用的消息的索引+ 1开始继续
Thread.sleep(1000)
(在消耗方法中)。发现
使用者从一开始就使用所有消息,而忽略了最后使用的消息。
期望
在关闭Spring Boot应用程序之前,使用者应从最后消耗的消息的索引+ 1开始消耗。
问题
如何使使用者从上次使用的消息的索引+ 1开始继续
KafkaConsumerConfig
@Configuration
@EnableKafka
public class KafkaConsumerConfig
{
@Bean
public Map<String, Object> consumerConfigs()
{
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "basic-group");
return props;
}
@Bean
public ConsumerFactory<Integer, String> consumerFactory()
{
return new DefaultKafkaConsumerFactory<>(consumerConfigs());
}
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Integer, String>>
kafkaListenerContainerFactory()
{
ConcurrentKafkaListenerContainerFactory<Integer, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(3);
factory.getContainerProperties().setPollTimeout(100);
return factory;
}
}
KafkaProducerConfig
@Configuration
public class KafkaProducerConfig
{
@Bean
public ProducerFactory<Integer, String> producerFactory()
{
return new DefaultKafkaProducerFactory<>(producerConfigs());
}
@Bean
public Map<String, Object> producerConfigs()
{
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return props;
}
@Bean
public KafkaTemplate<Integer, String> kafkaTemplate()
{
return new KafkaTemplate<>(producerFactory());
}
}
KafkaProducer
@Component
public class KafkaProducer
{
@Autowired
private KafkaTemplate kafkaTemplate;
public void sendMessage(String message, final String topicName)
{
ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(topicName, message);
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>()
{
@Override
public void onSuccess(SendResult<String, String> result)
{
System.out.println("Sent message=[" + message
+ "] with offset=[" + result.getRecordMetadata().offset() + "]");
}
@Override
public void onFailure(Throwable ex)
{
System.out.println("Unable to send message=["
+ message + "] due to : " + ex.getMessage());
}
});
}
}
KafkaConsumer
@Component
public class KafkaConsumer
{
@KafkaListener(id = "basic", topics = "test-1", clientIdPrefix = "test-prefix-id", autoStartup = "true", concurrency = "3")
public void multipleTransactionNotification(@Payload final String message)
{
try
{
Thread.sleep(1000);
System.out.println(message);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
TestApplication
@SpringBootApplication
public class TestApplication
{
public static void main(String[] args)
{
SpringApplication.run(TestApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx, KafkaProducer producer, NIPKafkaConsumer consumer) {
return args -> {
for (int i = 0; i < 100_000; i++)
{
producer.sendMessage("New Message-" + i, "test-1");
}
};
}
}
答案 0 :(得分:0)
Spring Kafka执行KafkaConsumer.poll()
来获取记录,然后为每个记录调用您的侦听器。
因此,如果该批次包含100条记录,将需要100秒才能使用您的实际KafkaListener进行整个批次。
消费者提交偏移量以知道从何处恢复。
默认行为是每5秒自动提交一次偏移。我的猜测是,您要在消费者支付其偏移量之前就杀死它,这就是为什么它从头开始重新启动的原因。
请参阅enable.auto.commit
和auto.commit.interval.ms
Kafka用户配置。
您还可以手动提交偏移量。
另请参见auto.offset.reset
来定义您的消费者在没有初始偏移量时应该怎么做。