Java 卡夫卡制作人和消费者问题
我对阿帕奇·卡夫卡有两个问题 第1期Java 卡夫卡制作人和消费者问题,java,spring-boot,apache-kafka,spring-kafka,Java,Spring Boot,Apache Kafka,Spring Kafka,我对阿帕奇·卡夫卡有两个问题 第1期 将100000条消息推送到卡夫卡 在使用者之前使用Ctrl-C关闭zookeeper和kafka服务 消耗所有100000条消息(这是通过使用 Thread.sleep(1000)在consume方法中) 发现 zookeeper和kafka服务关闭后,消费者继续在控制台上写入消息 期望值 @SpringBootApplication public class TestApplication { public static void main
Thread.sleep(1000)
在consume方法中)@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");
}
};
}
}
在zookeeper和kafka被调出后,消费者应该停止消费消息,并从最后一条消息的索引+1重新启动
问题
@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");
}
};
}
}
如何使消费者从上次消费的消息的索引+1继续
第二期
Thread.sleep(1000)
在consume方法中)@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");
}
};
}
}
消费者应该在spring引导应用程序关闭之前,从上次消费的消息的索引+1开始消费
问题
@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");
}
};
}
}
如何使消费者从上次消费的消息的索引+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;
}
}
@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());
}
}
测试应用程序
@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");
}
};
}
}
@springboot应用程序
公共类测试应用程序
{
公共静态void main(字符串[]args)
{
run(TestApplication.class,args);
}
@豆子
公共CommandLineRunner CommandLineRunner(ApplicationContext ctx、卡夫卡制作人、NIPKAF卡消费者){
返回参数->{
对于(int i=0;i<100_000;i++)
{
producer.sendMessage(“新消息-”+i,“test-1”);
}
};
}
}
第1期
Spring Kafka执行一个KafkaConsumer.poll()
来获取记录,然后为每个记录调用侦听器
因此,如果该批次包含100条记录,则使用实际的卡夫卡列斯汀继续整个批次需要100秒
问题2
消费者提交补偿以了解从何处恢复
默认行为是每5秒自动提交一次偏移量。我的猜测是,在消费者提交其偏移量之前杀死了消费者,这就是为什么它从一开始就重新启动
请参阅enable.auto.commit
和auto.commit.interval.ms
Kafka消费者配置
也可以手动提交偏移量
另请参见auto.offset.reset
,以定义消费者在没有初始偏移时应执行的操作。问题1
Spring Kafka执行一个KafkaConsumer.poll()
来获取记录,然后为每个记录调用侦听器
因此,如果该批次包含100条记录,则使用实际的卡夫卡列斯汀继续整个批次需要100秒
问题2
消费者提交补偿以了解从何处恢复
默认行为是每5秒自动提交一次偏移量。我的猜测是,在消费者提交其偏移量之前杀死了消费者,这就是为什么它从一开始就重新启动
请参阅enable.auto.commit
和auto.commit.interval.ms
Kafka消费者配置
也可以手动提交偏移量
另请参见
auto.offset.reset
,以定义消费者在没有初始偏移量时应执行的操作。Spring for Apache Kafka首选enable.auto.commit=false
;如果AckMode
属性设置为record
,侦听器容器将在每次poll()
之后或在处理每条记录时提交偏移量。Apache Kafka的Spring首选启用.auto.commit=false
;如果AckMode
属性设置为record
,则侦听器容器将在每次poll()
之后或在处理每条记录时提交偏移量。