Java 卡夫卡制作人和消费者问题

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

我对阿帕奇·卡夫卡有两个问题

第1期
  • 将100000条消息推送到卡夫卡
  • 在使用者之前使用Ctrl-C关闭zookeeper和kafka服务 消耗所有100000条消息(这是通过使用
    Thread.sleep(1000)
    在consume方法中)
  • 发现

    zookeeper和kafka服务关闭后,消费者继续在控制台上写入消息

    期望值

    @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继续

    第二期
  • 将100000条消息推送到卡夫卡
  • 在使用者之前使用Ctrl-C关闭zookeeper和kafka服务 消耗所有100000条消息(这是通过使用
    Thread.sleep(1000)
    在consume方法中)
  • 终止使用消息的spring引导应用程序
  • 提供动物园管理员和卡夫卡服务
  • 启动负责消费消息的spring引导应用程序
  • 发现

    使用者从一开始就使用所有消息,忽略上次使用的消息

    期望值

    @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()
    之后或在处理每条记录时提交偏移量。