kafka消费慢问题处理

SpringBoot集成Kafka:生产者速率与消费者性能优化,

生产者每秒生产1000条告警

import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

@Component
public class Runer implements ApplicationRunner {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        for (int i = 0; i < 60 * 1; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    send(atomicInteger);
                    atomicInteger.incrementAndGet();
                }
            }).start();
            Thread.sleep(1000L);
        }
        System.out.println("============共发送============="+atomicInteger.get());
    }

    /**
     * @param seq
     */
    public void send(AtomicInteger seq) {
        KafkaEnty kafkaEnty = new KafkaEnty();
        String str = seq + "Kafka 本身作为流处理平台,在大数据处理能力上应用广泛;同时 Kafka 也可以作为消息队列。本文将介绍基于 SpringBoot 2.6 集成 Kafka 2.8。";

        kafkaEnty.setSeq(seq);
        kafkaEnty.setContext(str);
        kafkaTemplate.send("myProducer", JSONUtil.toJsonStr(kafkaEnty));
    }
}

消费者将数据入库


import cn.hutool.json.JSONUtil;
import com.cloud.consumer.pojo.EmtyService;
import com.cloud.consumer.pojo.KafkaEnty;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * @Description: Kafka 消息消费者
 * @Author: junqiang.lu
 * @Date: 2022/2/25
 */
@Slf4j
@Component
public class KafkaMQConsumer {

    @Autowired
    private EmtyService emtyService;

    /**
     * 消息接受者
     * @param record
     */
    @KafkaListener(topics = "myProducer")
    public void receive(ConsumerRecord<?, ?> record) {
        log.info("record: {}", record);
        Optional.ofNullable(record.value())
                .ifPresent(message -> {
                    log.info("message: {}", message.toString());
                    emtyService.insert(JSONUtil.toBean(message.toString(), KafkaEnty.class));
                });
    }
    
}

发现每秒只能消费500条数据,于是我怀疑是拉去能力不足,于是设置每秒拉去2000条,最长0.5秒拉一次

spring:
  kafka:
    bootstrap-servers: 127.0.0.1:9092
    consumer:
      group-id: 1
      max-poll-records: 2000
      fetch-max-wait: 500

发现问题还是没有解决,于是我注销数据库入库操作,只打印,发现及时消费所有消息,于是给消息处理加上多线程,问题解决


    @KafkaListener(topics = "myProducer")
    public void receive(ConsumerRecord<?, ?> record) {
        log.info("record: {}", record);
        Optional.ofNullable(record.value())
                .ifPresent(message -> {
                    log.info("message: {}", message.toString());
                    //多线程处理
                    new Thread(()->{
                        emtyService.insert(JSONUtil.toBean(message.toString(), KafkaEnty.class));
                    }).start();
                });
    }

当然可以!下面是一个 **Kafka 消费异步处理的“简单写法”**,适用于大多数 Spring Boot 项目中需要快速实现“不阻塞消费线程”的场景。 --- ## ✅ 目标 - 使用 `@KafkaListener` 监听消息 - **快速返回监听方法**(避免 rebalance) - 将耗时业务逻辑交给 **异步线程池处理** - 手动提交 offset(可选) > 🎯 特点:代码简洁、易理解、适合初学者和中小型项目 --- ## 🧱 技术栈 - Spring Boot + `spring-kafka` - Java 8+ - 注解驱动开发 --- ## 🔧 第一步:添加依赖(pom.xml) ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> </dependencies> ``` --- ## ⚙️ 第二步:配置文件 `application.yml` ```yaml spring: kafka: bootstrap-servers: localhost:9092 consumer: group-id: async-group auto-offset-reset: earliest enable-auto-commit: false key-deserializer: org.apache.kafka.common.serialization.StringDeserializer value-deserializer: org.apache.kafka.common.serialization.StringDeserializer max-poll-interval-ms: 600000 # 10分钟,防止因处理导致 rebalance listener: ack-mode: MANUAL_IMMEDIATE # 手动提交 offset ``` --- ## 🏗️ 第三步:定义异步线程池 ```java // AsyncConfig.java @Configuration @EnableAsync public class AsyncConfig { @Bean("taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(100); executor.setThreadNamePrefix("async-kafka-"); executor.initialize(); return executor; } } ``` > ✅ `@EnableAsync` 启用异步支持 > ✅ 线程池命名清晰,便于排查问题 --- ## 💼 第四步:异步服务类(真正处理逻辑) ```java // KafkaAsyncService.java @Service @Slf4j public class KafkaAsyncService { @Async("taskExecutor") // 使用指定线程池执行 public void handleAsync(String key, String value, Acknowledgment acknowledgment) { try { log.info("【异步处理】开始处理消息: key={}, value={}", key, value); // 模拟耗时操作(如调接口、写数据库) Thread.sleep(5000); log.info("【异步处理】完成: {}", value); // ✅ 处理成功后提交 offset acknowledgment.acknowledge(); } catch (Exception e) { log.error("【异步处理】失败", e); // 可以选择:不提交 offset(重试)或发到死信队列 } } } ``` --- ## 🐬 第五步:Kafka Listener(轻量监听) ```java // KafkaConsumer.java @Component @Slf4j public class KafkaConsumer { @Autowired private KafkaAsyncService kafkaAsyncService; @KafkaListener(topics = "input-topic", groupId = "async-group") public void listen(ConsumerRecord<String, String> record, Acknowledgment acknowledgment) { log.info("【监听】收到消息: {}", record.value()); // 🔥 快速转发给异步服务,立即返回 kafkaAsyncService.handleAsync(record.key(), record.value(), acknowledgment); } } ``` > ✅ 这个方法非常快,不会阻塞 Kafka 的 `poll()` 循环 > ✅ 避免超过 `max.poll.interval.ms` 导致消费者被踢出组 --- ## ▶️ 第六步:测试生产者 Controller(可选) ```java // TestController.java @RestController public class TestController { @Autowired private KafkaTemplate<String, String> kafkaTemplate; @GetMapping("/send") public String send(@RequestParam String msg) { kafkaTemplate.send("input-topic", "key1", msg); return "Sent: " + msg; } } ``` --- ## 🚀 启动类 ```java @SpringBootApplication @EnableKafka @EnableAsync public class KafkaAsyncApplication { public static void main(String[] args) { SpringApplication.run(KafkaAsyncApplication.class, args); } } ``` --- ## ✅ 测试流程 1. 创建主题: ```bash kafka-topics.sh --create --topic input-topic --partitions 3 --replication-factor 1 --bootstrap-server localhost:9092 ``` 2. 启动应用 3. 发送消息: ``` GET http://localhost:8080/send?msg=hello ``` 4. 观察日志: - 【监听】收到消息 → 立即返回 - 【异步处理】几秒后打印处理日志 - offset 正常提交 --- ## 📝 总结:这个“简单写法”的特点 | 优点 | 说明 | |------|------| | ✅ 简洁明了 | 仅需几个类即可完成异步消费 | | ✅ 不阻塞 poll | 监听方法快速返回,防 rebalance | | ✅ 支持手动提交 | 保证消息至少处理一次(at-least-once) | | ✅ 易扩展 | 可加入重试、DLQ、监控等 | --- ## ⚠️ 注意事项 - `Acknowledgment` 可跨线程使用(Spring Kafka 支持),但只能提交一次。 - 如果异步处理失败且不想重试,建议发送到 **死信队列(DLQ)** 并手动提交 offset。 - 不要在 `@Async` 方法里再调用 Kafka Consumer API。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值