当前位置:首页 > 技术 > 正文内容

Spring Boot 集成 Kafka 实战指南

访客 技术 2026年7月9日 1

1. 概述

Apache Kafka 是一个分布式流处理平台,以高吞吐量、数据持久化和容错性著称,广泛应用于实时数据管道构建。

Spring Boot 作为主流的微服务开发框架,提供了开箱即用的集成能力,让 Kafka 的接入变得简单。将 Spring Boot 与 Kafka 组合,能带来以下好处:

  • 异步处理:利用消息队列实现生产者和消费者解耦,提升系统响应速度。
  • 系统解耦:模块间通过消息通信,降低直接依赖,增强可维护性。
  • 流式处理:支持实时数据分析、日志聚合和事件驱动架构。
  • 高可靠性:Kafka 的副本机制和持久化策略确保消息不丢失,保证系统稳定性。

2. Kafka 核心概念

在集成之前,先回顾 Kafka 的几个关键特性:

  • 发布/订阅模型:生产者发送消息到主题(Topic),消费者订阅主题消费消息。
  • 消息日志与偏移量:消息以日志形式持久化存储,每条消息在分区(Partition)内有唯一递增的偏移量(Offset)。
  • 分布式架构:集群由多个 Broker 组成,分区可复制到多个 Broker,保证高可用和数据冗余。
  • 高吞吐与低延迟:通过批量处理、零拷贝等技术实现高性能。
  • 水平扩展:通过增加 Broker 和分区即可线性提升集群处理能力。
  • 流处理:Kafka Streams API 支持在集群内直接进行实时数据处理。

3. 在 Spring Boot 中集成 Kafka

3.1. 添加依赖

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

// Gradle
implementation 'org.springframework.kafka:spring-kafka:2.9.13'

3.2. 配置 application.yml

统一管理 Kafka 相关配置,包括主题名称、消费者组 ID、序列化/反序列化方式等:

custom:
  topics:
    info: "ENTRY_USER_INFO"
  group:
    id: "hrfan-consumer-group"

spring:
  kafka:
    consumer:
      bootstrap-servers: 192.168.112.128:9092
      group-id: ${custom.group.id}
      auto-offset-reset: earliest
      key-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
      value-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
      properties:
        spring.json.trusted.packages: '*'
        spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer
        spring.deserializer.value.delegate.class: org.apache.kafka.common.serialization.StringDeserializer
    producer:
      bootstrap-servers: 192.168.112.128:9092
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer

4. 生产者实现

利用 KafkaTemplate 即可快速发送消息,支持多种发送模式:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Component
public class SimpleProducer {
    private static final Logger log = LoggerFactory.getLogger(SimpleProducer.class);

    @Value("${custom.topics.info}")
    private String topicName;

    @Resource
    private KafkaTemplate<String, String> strTemplate;

    @Resource
    private KafkaTemplate<String, Message<String>> msgTemplate;

    public void sendMessages() {
        // 1. 无 Key 消息
        strTemplate.send(topicName, "这是一条普通消息");

        // 2. 带 Key 的消息
        strTemplate.send(topicName, "my-key-1", "带有Key的消息");

        // 3. 指定分区和 Key
        strTemplate.send(topicName, 0, "my-key-2", "指定分区消息");

        // 4. 发送 Message 对象(可携带自定义头信息)
        Map<String, Object> headersMap = new HashMap<>();
        headersMap.put("traceId", UUID.randomUUID().toString());
        MessageHeaders headers = new MessageHeaders(headersMap);
        Message<String> message = MessageBuilder.createMessage("这是一个Message格式的消息", headers);

        msgTemplate.setDefaultTopic(topicName);
        msgTemplate.sendDefault("my-key-3", message);

        log.info("所有消息发送完毕");
    }
}

5. 消费者实现

通过 @KafkaListener 注解即可声明一个消费者:

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class SimpleConsumer {
    private static final Logger log = LoggerFactory.getLogger(SimpleConsumer.class);

    @KafkaListener(
        topics = "#{'${custom.topics.info}'.split(',')}",
        groupId = "${custom.group.id}",
        autoStartup = "true"
    )
    public void handleMessage(ConsumerRecord<String, String> record,
                              @Headers Map<String, Object> headers) {
        log.info("接收到的消息记录:{}", record);
    }
}

6. ACK 机制详解

ACK(Acknowledgement)是生产者的消息确认机制,决定了数据的可靠性级别:

  • acks=0:不等待确认,性能最高,风险最大。
  • acks=1:等待 Leader 写入成功,默认值,兼顾性能与可靠性。
  • acks=all:等待所有 ISR 副本确认,安全性最高,延迟最大。

6.1. Spring Kafka 中的 AckMode

Spring Kafka 提供了多种确认模式,通过 AckMode 枚举定义:

  • RECORD:每条消息处理完后立即提交 Offset。
  • BATCH:每批消息处理完后提交一次 Offset。
  • TIME:每隔固定时间间隔提交一次 Offset。
  • COUNT:每处理 N 条消息后提交一次 Offset。
  • COUNT_TIME:结合数量和时间阈值,先到先提交。
  • MANUAL:手动调用 Acknowledgment.acknowledge() 提交。
  • MANUAL_IMMEDIATE:手动提交后立即执行,不等待。

6.2. 手动提交示例

将自动提交关闭并设置 ack-modeMANUAL_IMMEDIATE

spring:
  kafka:
    consumer:
      enable-auto-commit: false
      properties:
        ack-mode: MANUAL_IMMEDIATE

消费者代码中注入 Acknowledgment 参数,在需要时手动提交:

@KafkaListener(topics = "#{'${custom.topics.info}'.split(',')}",
               groupId = "${custom.group.id}",
               autoStartup = "true")
public void manualCommit(ConsumerRecord<String, String> record,
                         @Headers Map<String, Object> headers,
                         Acknowledgment acknowledgment) {
    log.info("处理消息:{}", record);

    // 业务处理完成后手动提交 Offset
    acknowledgment.acknowledge();
}

7. 常用配置参考

7.1. 生产端关键配置

属性说明
request.required.acksACK 确认级别,0/1/-1(即all)
producer.typesync(同步)或 async(异步)
batch.num.messages异步模式下每批次发送的消息数
message.send.max.retries发送失败重试次数

7.2. 消费端关键配置

属性说明
group.id消费者组 ID,用于负载均衡
enable.auto.commit是否允许自动提交 Offset
auto.offset.reset无初始 Offset 时策略(earliest/latest/none)
fetch.min.bytes每次拉取的最小字节数

7.3. 服务端关键配置

属性说明
broker.id节点唯一标识
log.dirs日志存储目录
num.partitions默认分区数
log.retention.hours数据保留时间(小时)
zookeeper.connectZooKeeper 连接地址

8. 命令行消费数据

在服务器上可以直接使用 Kafka 提供的命令行工具查看消息:

kafka-console-consumer \
  --bootstrap-server 192.168.112.129:9092 \
  --topic ENTRY_LIST_SEND_INFO \
  --from-beginning

该命令会从指定主题的最开始位置读取所有消息并在控制台输出。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。