spring boot kafka 支持批量操作

版权声明:本文为博主原创文章,转载请附上博文链接,谢谢! https://blog.csdn.net/qq_30062125/article/details/83095290

前言

最近有个项目存在kafka积压情况,上去看了下,的确积压挺厉害。
看了下代码,spring boot 是1.5.13.RELEASE版本,kafka使用的是spring boot的自动配置,@KafkaListener每次处理一条数据,每次逻辑中存在多次数据库操作。
准备修改下逻辑,@KafkaListener批量处理数据,合并逻辑,并且批量操作数据库,提高处理速度。

原有逻辑

1.pom添加配置

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

2.application.yml添加配置

spring:
    kafka:
        bootstrap-servers: 127.0.0.1:9092
        #生产者的配置,大部分我们可以使用默认的,这里列出几个比较重要的属性
        producer:
            #每批次发送消息的数量
            batch-size: 16
            #设置大于0的值将使客户端重新发送任何数据,一旦这些数据发送失败。注意,这些重试与客户端接收到发送错误时的重试没有什么不同。允许重试将潜在的改变数据的顺序,如果这两个消息记录都是发送到同一个partition,则第一个消息失败第二个发送成功,则第二条消息会比第一条消息出现要早。
            retries: 0
            #producer可以用来缓存数据的内存大小。如果数据产生速度大于向broker发送的速度,producer会阻塞或者抛出异常,以“block.on.buffer.full”来表明。这项设置将和producer能够使用的总内存相关,但并不是一个硬性的限制,因为不是producer使用的所有内存都是用于缓存。一些额外的内存会用于压缩(如果引入压缩机制),同样还有一些用于维护请求。
            buffer-memory: 33554432
            #key序列化方式
            key-serializer: org.apache.kafka.common.serialization.StringSerializer
            value-serializer: org.apache.kafka.common.serialization.StringSerializer
        #消费者的配置
        consumer:
            concurrency: 10
            #Kafka中没有初始偏移或如果当前偏移在服务器上不再存在时,默认区最新 ,有三个选项 【latest, earliest, none】
            auto-offset-reset: earliest
            #是否开启自动提交
            enable-auto-commit: false
            ack-mode: MANUAL_IMMEDIATE
            #自动提交的时间间隔
            #            auto-commit-interval: 100
            #key的解码方式
            key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
            #value的解码方式
            value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
            group-id: test-consumer-group
          

3.java监听逻辑

@KafkaListener(topics = { "topic" })
	public void listenPlayEnt(ConsumerRecord<?, ?> record) {
   // 处理逻辑
   ....
}

简单思路

spring kafka实现

由于spring boot 自动配置KafkaAutoConfiguration和KafkaProperties中没有找到批量操作相关的,转向查看依赖实现spring-kafka。

从 官方文档 https://docs.spring.io/spring-kafka/reference/html/_reference.html 中我们可以看出来批量需要以下代码实现。

@Configuration
@EnableKafka
public class KafkaConfig {

    @Bean
    KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Integer, String>>
                        kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<Integer, String> factory =
                                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        factory.setConcurrency(3);
        # 这个就是用来控制是否批量处理
        factory.setBatchListener(true);
        factory.getContainerProperties().setPollTimeout(3000);
        return factory;
    }

    @Bean
    public ConsumerFactory<Integer, String> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerConfigs());
    }

    @Bean
    public Map<String, Object> consumerConfigs() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, embeddedKafka.getBrokersAsString());
        ...
        return props;
    }
}

但是,我人比较懒,不想大幅度修改kafka相关的配置,想要沿用spring boot kafka自动配置逻辑。

具体的过程不说了,简单分析下KafkaAutoConfiguration逻辑,可以看到差别主要是在ConcurrentKafkaListenerContainerFactory这个bean。

spring boot kafka实现

1.重写KafkaProperties对象

import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@ConfigurationProperties(prefix = "spring.kafka")
@Configuration("KafkaPropertiesExtra")
@Primary
public class KafkaPropertiesExtra extends KafkaProperties {

    private final ConsumerExtra consumerExtra = new ConsumerExtra();

    public static class ConsumerExtra {

        private Boolean batchListener = false;

        public Boolean getBatchListener() {
            return batchListener;
        }

        public void setBatchListener(Boolean batchListener) {
            this.batchListener = batchListener;
        }
    }


    public ConsumerExtra getConsumerExtra() {
        return this.consumerExtra;
    }



}

2.自定义ConcurrentKafkaListenerContainerFactory这个bean

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.kafka.ConcurrentKafkaListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;

@Configuration
public class KafkaConfig {

    @Autowired KafkaPropertiesExtra kafkaProperties;

    @Bean
    public ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(
        ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
        ConsumerFactory<Object, Object> kafkaConsumerFactory) {
        ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<Object, Object>();
        configurer.configure(factory, kafkaConsumerFactory);

        // 补充批量处理参数
        factory.setBatchListener(kafkaProperties.getConsumerExtra().getBatchListener());

        return factory;
    }

}

3.修改application.yml,加上批量相关的配置

spring:
    kafka:
        ......
        consumer:
            ......
            # 一次性最多抓取多少条数据
            max-poll-records: 100
            # 超时时间 毫秒
            poll-timeout: 3000
            max-poll-interval-ms: 5000
        consumer-extra:
            # 是否批量处理
            batch-listener: true

4.修改java监听器逻辑,改成list

@KafkaListener(topics = { "topic" })
	public void listenPlayEnt(List<ConsumerRecord<?, ?>> records) {
	// 处理逻辑
   ....
}

至此,就基于spring boot的KafkaAutoConfiguration实现了kafka批量消费逻辑。

猜你喜欢

转载自blog.csdn.net/qq_30062125/article/details/83095290