Kafka 之消息并发消费

前言:

我们知道 Kafka 以其高性能著称,Kafka 的性能极其强大,那在 Java 应用中,我们怎么来利用其 Kafka 的高性能呢?

Kafka 系列文章传送门

Kafka 简介及核心概念讲解

Spring Boot 整合 Kafka 详解

Kafka @KafkaListener 注解的详解及使用

Kafka 客户端工具使用分享【offsetexplorer】

Kafka 之消息同步/异步发送

Kafka 之批量消息发送消费

Kafka 之消息广播消费

Kafka 之消息并发消费

我们使用 @KafkaListener 进行消息消费的时候,默认是单线程消费的,当生产者数据量很大的时候,单线程消费很容器导致消费堆积,浪费了 Kafka 的优异性能,我们在开发 Java 应用程序的时候,如果发现单线程效率低不能满足业务场景的时候,我们自然而然的想到了使用多线程来处理,同样 Kafka 是支持多线程消费的,而且 spring-cloud-starter-stream-kafka 已经帮我们实现好了,我们只需要按需配置即可。

我们在来看看 @KafkaListener 注解,该注解有一个属性叫 concurrency,该属性可以指定并发小消费的现成数量,我们可以进行如下配置:

java 复制代码
@KafkaListener(id = "my-kafka-consumer",
            groupId = "my-kafka-consumer-groupId",
            topics = "my-topic",
            concurrency = "3",
            containerFactory = "myContainerFactory")

concurrency = "3",表示启动三个线程来消费,接下来我们来演示一下 Kafka 的批量消费。

Kafka 并发消费之 Producer 代码

生产者代码还是没有什么特殊,我写了一个 for 循环来发送 100 条消息,如下:

java 复制代码
package com.order.service.kafka.producer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName: MyKafkaConcurrencyProducer 
 * @Author: Author
 * @Date: 2024/10/22 19:22
 * @Description:
 */
@Slf4j
@Component
public class MyKafkaConcurrencyProducer {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    public void batchSendMessage() {
        for (int a = 0; a < 100; a++) {
            this.kafkaTemplate.send("my-topic", "第" + a + "条 kafka 消息");
        }
    }

}

Kafka 并发消费之消费者代码

并发消费我们还是使用 @KafkaListener 注解来完成消息消费监听,具体代码如下:

java 复制代码
package com.order.service.kafka.consumer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName: MyKafkaConcurrencyConsumer
 * @Author: zhangyong
 * @Date: 2024/10/22 19:22
 * @Description:
 */
@Slf4j
@Component
public class MyKafkaConcurrencyConsumer {

    @KafkaListener(id = "my-kafka-concurrency-consumer",
            groupId = "my-kafka-consumer-groupId",
            topics = "my-topic",
            concurrency = "3",
            containerFactory = "myContainerFactory")
    public void listen(String message) {
        log.info("消息消费成功,线程ID:{},消息内容:{}", Thread.currentThread().getId(), message);
    }

}

注意这里相交前面分享的案例,我们在注解的属性上加了 concurrency = "3",正是这个属性才能放 Kafka 完成并发消费。

Kafka 并发消费之结果验证

我们触发消息发送,控制台部分日志如下:

powershell 复制代码
2024-10-27 18:10:12.089  INFO 7308 --- [-consumer-2-C-1] c.o.s.k.c.MyKafkaConcurrencyConsumer     : 消息消费成功,线程ID:146,消息内容:第12条 kafka 消息
2024-10-27 18:10:12.097  INFO 7308 --- [-consumer-1-C-1] c.o.s.k.c.MyKafkaConcurrencyConsumer     : 消息消费成功,线程ID:144,消息内容:第46条 kafka 消息
2024-10-27 18:10:12.100  INFO 7308 --- [-consumer-2-C-1] c.o.s.k.c.MyKafkaConcurrencyConsumer     : 消息消费成功,线程ID:146,消息内容:第13条 kafka 消息
2024-10-27 18:10:12.123  INFO 7308 --- [-consumer-0-C-1] c.o.s.k.c.MyKafkaConcurrencyConsumer     : 消息消费成功,线程ID:142,消息内容:第68条 kafka 消息
2024-10-27 18:10:12.132  INFO 7308 --- [-consumer-1-C-1] c.o.s.k.c.MyKafkaConcurrencyConsumer     : 消息消费成功,线程ID:144,消息内容:第47条 kafka 消息

通过控制台日志可以看到,线程 ID 分别有 144、146、142,表示确实有多个线程在进行消息监听,结果符合预期。

Kafka 并发消费的时候指定多个个线程合适?

在进行 Kafka 消息并发消费的时候,并不是设定的线程数量越多,效率就越高,线程数的多少跟 Kafka 的 Partition 是有直接关系的,一个 Partition 只能被一个线程消费,因此我们最多将并发线程数量和 Kafka Topic 的 Partition 数量设置一致,或者不要超过 Kafka Topic 的 Partion 的数量,下面我们来分析一下线程数量设置不合理会有什么情况发生。

  • 并发线程数 concurrency > Partition ,会导致有多余的线程没有消息可以消费,会造成资源浪费。
  • 并发线程数 concurrency = Partition ,最佳状态,一个消费者线程消费一个 Partition 的数据。
  • 并发线程数 concurrency < Partition ,会有一个线程消费多个 Partition 的情况,可能会导致消费不均衡的情况出现。

一般没有特殊情况下,使用并发消费的时候,建议都将线程数和消费的 Kafka Topic 的 Partition 数量保持一致。

如有不正确的地方欢迎各位指出纠正。

相关推荐
天冬忘忧1 小时前
Kafka 工作流程解析:从 Broker 工作原理、节点的服役、退役、副本的生成到数据存储与读写优化
大数据·分布式·kafka
潜洋1 小时前
Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序
java·spring boot·后端
gjh12081 小时前
什么是微服务?
微服务
灯雾️2 小时前
Spring Boot、Spring MVC和Spring间的区别
spring boot
supercool72 小时前
SpringBoot(9)-Dubbo+Zookeeper
spring boot·dubbo·java-zookeeper
没有黑科技3 小时前
基于web的音乐网站(Java+SpringBoot+Mysql)
java·前端·spring boot
计算机毕设孵化场3 小时前
计算机毕设-基于springboot的多彩吉安红色旅游网站的设计与实现(附源码+lw+ppt+开题报告)
vue.js·spring boot·后端·计算机外设·课程设计·计算机毕设论文·多彩吉安红色旅游网站
战神刘玉栋3 小时前
《SpringBoot、Vue 组装exe与套壳保姆级教学》
vue.js·spring boot·后端
工业甲酰苯胺3 小时前
Python脚本消费多个Kafka topic
开发语言·python·kafka
码到成功>_<4 小时前
Spring Boot实现License生成和校验
数据库·spring boot·后端