【问题标题】:Kafka & Spring Batch - How to read ONLY uncommitted messages from the same topic?Kafka 和 Spring Batch - 如何仅读取来自同一主题的未提交消息?
【发布时间】:2021-04-26 08:58:33
【问题描述】:

我正在使用 Spring batch 和 Kafka 处理小批量,它从 Kafka 主题读取 json 数据,将其转换为 Student 对象,更改值并将其发送回 Kafka 主题。 一切正常,但我唯一的问题是我的消费者总是从主题的乞求中阅读。 我需要它从最后一条未消费的消息中读取。 我已经添加了这些属性:

ConsumerConfig.AUTO_OFFSET_RESET_CONFIG to earliest
ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG to false
ConsumerConfig.GROUP_ID_CONFIG to a random value

但这似乎不起作用,在消费者启动时,它会处理所有消息。有人知道如何使用 Spring Batch 和 Kafka 吗?这是我的代码:

BatchStudent.java

@SpringBootApplication
@EnableBatchProcessing
@RequiredArgsConstructor
public class BatchStudent {
    public static void main(String[] args) {
        SpringApplication.run(BatchStudent.class, args);
    }

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;
    private final KafkaTemplate<Integer, Student> template;
    private final KafkaProperties properties;

    @Value("${kafka.topic.consumer}")
    private String topic;

    @Bean
    public ItemProcessor<Student, Student> customItemProcessor() {
        return new CustomProcessor();
    }

    @Bean
    Job job() {
        return this.jobBuilderFactory.get("job")
                .start(start())
                .incrementer(new RunIdIncrementer())
                .build();
    }

    @Bean
    KafkaItemWriter<Integer, Student> writer() {
        return new KafkaItemWriterBuilder<Integer, Student>()
                .kafkaTemplate(template)
                .itemKeyMapper(Student::getId)
                .build();
    }

    @Bean
    public KafkaItemReader<Integer, Student> reader() {
        Properties props = new Properties();
        props.putAll(this.properties.buildConsumerProperties());

        return new KafkaItemReaderBuilder<Integer, Student>()
                .partitions(0)
                .consumerProperties(props)
                .name("students-consumer-reader")
                .saveState(true)
                .topic(topic)
                .build();
    }

    @Bean
    Step start() {
        return this.stepBuilderFactory
                .get("step")
                .<Student, Student>chunk(10)
                .writer(writer())
                .processor(customItemProcessor())
                .reader(reader())
                .build();
    }
}

app.yml

spring.batch.initialize-schema: always

#Conf Kafka Consumer
spring.kafka.consumer.key-deserializer: org.apache.kafka.common.serialization.IntegerDeserializer
spring.kafka.consumer.value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
#spring.kafka.consumer.group-id: student-group
spring.kafka.consumer.properties.spring.json.trusted.packages: '*'
spring.kafka.consumer.properties.spring.json.value.default.type: com.org.model.Student

#Conf Kafka Producer
spring.kafka.producer.key-serializer: org.apache.kafka.common.serialization.IntegerSerializer
spring.kafka.producer.value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.producer.bootstrap-servers: localhost:9092

#Conf topics
spring.kafka.template.default-topic: producer.student
kafka.topic.consumer: consumer.student

Student.java

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    Integer id;
    Integer count;
}

CustomProcessor.java

@NoArgsConstructor
public class CustomProcessor implements ItemProcessor<Student, Student> {

    @Override
    public Student process(Student studentRecieved) {
        final Student studentSent = new Student();
        studentSent.setId(studentRecieved.getId());
        studentSent.setCount(200);
        return studentSent;
    }
}

感谢您的帮助!

【问题讨论】:

  • 设置 auto-offset-reset: latest 会发生什么?
  • 同样的行为,我认为它的默认值是最新的
  • 如果您将 groupId 设置为随机值(大概是每次启动消费者时),那么它应该如何从上一次运行中获取偏移量?它们将保存在完全不同的 groupId 下。

标签: java spring apache-kafka spring-batch spring-kafka


【解决方案1】:

一切正常,但我唯一的问题是我的消费者总是从主题的乞求中阅读。我需要它从最后一条未消费的消息中读取。

Spring Batch 4.3 引入了一种使用 Kafka 中存储的偏移量记录的方法。我在去年 Spring One 的演讲中谈到了这个功能:What's new in Spring Batch 4.3?。您可以使用 setPartitionOffsets 在每个分区中为 kafka 阅读器配置自定义起始偏移量:

Setter for partition offsets. This mapping tells the reader the offset to start reading
from in each partition. This is optional, defaults to starting from offset 0 in each
partition. Passing an empty map makes the reader start from the offset stored in Kafka
for the consumer group ID.

你可以在this test case找到一个完整的例子。

【讨论】:

  • 嗨@Mahmoud Ben Hassine。我认为还有一个问题。 ParitionsOffset 始终使用我们读取的最后一个偏移量进行初始化。重新运行 JOB 后。阅读器从相同的偏移量开始读取,而不是零。我知道我可以使用设置来设置它们,但是在新作业的当前上下文中我没有这些信息。我只需要调用 kafkaConsumer 并获取偏移量,然后将其递增 1。
  • 偏移量存储在spring batch的执行上下文和kafka中。在重新启动失败的作业实例时,您可以选择从哪里读取它。默认情况下,重新启动将使作业从存储在 Spring Batch 的执行上下文中的最后一个偏移量中读取数据。如果要从 Kafka 中存储的偏移量重新开始,可以传递一个空的 partitionOffset 映射。
  • 我明白了你的意思,对于重新启动,我也可以这样做。问题在于新的 JOb 实例。基本上它在 KafkaItemReader 的 Open 方法中没有通过这个检查,如果 (this.saveState && executionContext.containsKey(TOPIC_PARTITION_OFFSETS)) 。它从地图分区偏移量中的最后一个偏移量开始读取。我必须获得该偏移量的唯一选择是通过 KafkaOffset 或者我应该在一些全局上下文中设置。
  • 它也不会自动从存储在执行上下文中的最后一个偏移量开始。我遵循了您的测试用例,从执行上下文中获取后,我们应该需要使用 Topic Partions 设置 PartitionOffset。基本上,KafkaItemReader 需要重新初始化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2021-07-09
  • 2020-05-22
  • 2018-01-09
  • 2018-07-18
  • 1970-01-01
相关资源
最近更新 更多