Springboot整合kafka(MQ)

概念

  • 一个topic主题下面有多个分区(比如partition1、partition2、partition3),每个分区有多个副本;从所有的副本中选取一个作为Leader,其他作为Follower,Leader副本 负责消息的接收和消息的消费,Follower只负责数据的同步;当Leader分区故障后,从Follower中选取一个作为新的Leader

  • 一个分区partition只能被消费者组中的一个消费者实例消费,当topic中分区数量发生变化 或者 消费者组中的消费者发生变化 会触发rebalance,重新分配分区partition和消费者实例 之间的关系

  • 生产者发送的消息只在一个partition分区内有序,如果topic下面有多个分区,那所有消息整体是无序的

  • 一个topic可以有多个消费者组,kafka会记录每个"消费者组" 消费到 "哪个分区的哪个偏移量offset"了

下载

  • 下载地址:kafka.apache.org/community/d...

  • /root/kafka/kafka_2.12-3.6.2目录下创建文件夹mq_logs,并在mq_logs文件夹下分别创建文件夹kafka_data_logszookeeper_data分别保存kafka的日志数据和zookeeper的数据

  • mq_logs目录下创建kafka_console.outzookeeper_console.out保存启动程序时的日志输出

  • 进入config目录修改zookeeper.properties,将dataDir改为:dataDir=/root/kafka/kafka_2.12-3.6.2/mq_logs/zookeeper_data

  • 进入config目录修改server.properties

    • 将log.dir改为log.dirs=/root/kafka/kafka_2.12-3.6.2/mq_logs/kafka_data_logs

    • 添加配置:listeners=PLAINTEXT://0.0.0.0:9092 advertised.listeners=PLAINTEXT://localhost:9092

启动

  • 先启动zookeeper:nohup bin/zookeeper-server-start.sh config/zookeeper.properties > /root/kafka/kafka_2.12-3.6.2/mq_logs/zookeeper_console.out 2>&1 &

  • 再启动kafka:nohup bin/kafka-server-start.sh config/server.properties > /root/kafka/kafka_2.12-3.6.2/mq_logs/kafka_console.out 2>&1 &

命令

  • 创建主题:./kafka-topics.sh --create --topic 主题名称 --bootstrap-server localhost:9092

  • 查看所有主题:./kafka-topics.sh --list --bootstrap-server localhost:9092

  • 查看某个主题:./kafka-topics.sh --describe --topic 主题名称 --bootstrap-server localhost:9092

  • 删除某个主题:./kafka-topics.sh --delete --topic 主题名称 --bootstrap-server localhost:9092

  • 查看某个组的消费情况:./kafka-consumer-groups.sh --describe --group 消费者组名称 --bootstrap-server localhost:9092

  • 查看某个组下面的消费者:./kafka-consumer-groups.sh --describe --group 消费组名称 --bootstrap-server localhost:9092 --members

springboot整合kafka

  • 引入依赖

    java 复制代码
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
    </dependency>
  • 引入配置

    properties 复制代码
    spring.kafka.bootstrap-servers=115.190.156.159:9092
    spring.kafka.producer.retries=3
    spring.kafka.producer.batch-size=1000
    spring.kafka.producer.buffer-memory=33554432
    
    spring.kafka.consumer.group-id=crm-microservice-newperformance
    spring.kafka.consumer.enable-auto-commit=false
    spring.kafka.consumer.auto-offset-reset=earliest
    spring.kafka.consumer.max-poll-records=200
    spring.kafka.listener.ack-mode=MANUAL_IMMEDIATE
  • 配置类:如果程序异常,spring默认将这条消息重复处理9次;这里配置的是同一消息 多次消费失败 的处理策略,即转发到另一个死信topic中;注意,这里是springboot2.7及以上版本的配置方式,和2.7以下版本配置方法不同

    java 复制代码
    @Component
    public class KafkaConfig {
        @Bean
        public CommonErrorHandler errorHandler(KafkaTemplate<Object, Object> template) {
            // 1. 定义死信恢复器,当重试耗尽后,将消息转发到 "原Topic.DLT"
            DeadLetterPublishingRecoverer recover = new DeadLetterPublishingRecoverer(template);
            
            // 2. 定义错误处理器
            DefaultErrorHandler errorHandler = new DefaultErrorHandler(recover, new FixedBackOff(1000L, 3));
    
            return errorHandler;
        }
    }
  • 生产者

    java 复制代码
    @CrossOrigin
    @RestController
    @RequestMapping("/kafka")
    public class KafkaController {
        @Autowired
        private KafkaTemplate<String, String> kafkaTemplate;
    
        @RequestMapping("/send")
        public String send() throws InterruptedException, ExecutionException {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("userid", 1001);
            map.put("name", "ccb"+ UUID.randomUUID());
    
            ListenableFuture<SendResult<String, String>> result = kafkaTemplate.send("test_ccb", JSONObject.toJSONString(map));
            System.out.println("发送结果:"+result.get());
            return "ok";
        }
    }
  • 消费者

    java 复制代码
    public class KafkaConsumer {
    
        // 这里的concurrency=5代表会创建5个消费者实例
        @KafkaListener(topics = {"test_ccb"},concurrency = "5")
        public void consumer(ConsumerRecord<?, ?> consumerRecord, Acknowledgment ack) {
            System.out.println("收到消息:" + consumerRecord);
            ack.acknowledge();
        }
    }

Spring-Kafka原理

  • spring-kafka的自动配置类中,通过KafkaListenerAnnotationBeanPostProcessor 扫描每个Bean对象是否带有@KafkaListener注解,如果有则提取注解上的topicsgroupIdconcurrency等信息封装成一个Endpoint对象,根据Endpoint指定的容器工厂containerFactory创建容器,在容器内运行KafkaConsumer
  • 容器工厂是ConcurrentKafkaListenerContainerFactory,它生产容器KafkaMessageListenerContainer,在容器内运行KafkaConsumer,如果concurrency设置为3,将创建3个容器,也就是会有3个消费者实例
  • 如果程序处理过程中出现了错误,会调用配置好的 CommonErrorHandler进行处理,默认会重试9次,如果还是失败,则提交该偏移量避免阻塞后续消息
  • gemini3剖析过程:gemini.google.com/share/4de80...

相关文章

相关推荐
清名2 小时前
AI应用-基于LangChain4j实现AI对话
人工智能·后端
踏浪无痕2 小时前
夜莺告警引擎内核:一个优雅的设计
运维·后端·go
小小荧2 小时前
Hono与Honox一次尝试
前端·后端
a努力。2 小时前
京东Java面试:如何设计一个分布式ID生成器
java·分布式·后端·面试
superman超哥2 小时前
Rust 复合类型:元组与数组的内存布局与性能优化
开发语言·后端·性能优化·rust·内存布局·rust复合类型·元组与数组
计算机毕设指导62 小时前
基于Django的本地健康宝微信小程序系统【源码文末联系】
java·后端·python·mysql·微信小程序·小程序·django
曲莫终3 小时前
增强版JSON对比工具类
java·后端·测试工具·json
BD_Marathon3 小时前
Spring——核心概念
java·后端·spring
码农水水3 小时前
宇树科技Java被问:数据库连接池的工作原理
java·数据库·后端·oracle