加群联系作者vx:xiaoda0423
仓库地址:https://webvueblog.github.io/JavaPlusDoc/
https://1024bat.cn/
Kafka Producer 端(生产者)配置
Kafka Consumer 端(消费者)配置
区分了不同的消费模式(批量消费、单条消费),并且生产者也是分别独立管理。
阶段 |
内容 |
---|---|
配置阶段 |
通过 |
属性注入 |
通过 |
Bean 定义 |
生产者定义 |
使用阶段 |
在业务代码中注入对应的 |
阶段 |
数据结构 |
变化说明 |
---|---|---|
生产者发送前 |
Java对象/String |
Java对象通常先转为 String(通过序列化器) |
传输到 Kafka |
byte[] |
Kafka 内部只认识字节数组 |
消费者接收 |
byte[] → String |
消费者接收到字节流,反序列化回 String |
消费逻辑处理 |
Java对象/String |
再根据业务场景反序列化成 Java 对象处理 |
Spring Boot 扫描到 @Configuration
,注册 KafkaTemplate 和 KafkaListenerContainerFactory。
@Autowired
@Qualifier("kafkaTemplate")
private KafkaTemplate kafkaTemplate;
public void sendMessage(String topic, String message) {
kafkaTemplate.send(topic, message);
}
@KafkaListener(topics = "test-topic", containerFactory = "kafkaBRConsumerFactory")
public void listenBatch(List> records) {
for (ConsumerRecord record : records) {
System.out.println("Received message: " + record.value());
}
}
// 或者单条消费
@KafkaListener(topics = "test-topic", containerFactory = "kafkaOBORConsumerFactory")
public void listenSingle(ConsumerRecord record) {
System.out.println("Received single message: " + record.value());
}
生产者和消费者配置完全隔离,职责清晰。
支持批量消费(性能高)和逐条消费(处理更精细)两种模式。
KafkaTemplate 统一封装消息发送,内部使用的是 ProducerFactory。
KafkaListenerContainerFactory 统一封装消息监听,内部使用的是 ConsumerFactory。
生产消费流程:Java对象 → Kafka字节流传输 → Java对象。
application.yml
Kafka配置模板kafka:
producer:
servers: 127.0.0.1:9092
retries: 3 # 发送失败重试次数
batch:
size: 16384 # 批量发送最大字节数
linger: 1 # 等待时间(ms)
buffer:
memory: 33554432 # 32MB缓冲区大小
consumer:
servers: 127.0.0.1:9092
enable:
auto:
commit: false # 是否自动提交offset
session:
timeout: 30000 # session超时时间
auto:
commit:
interval: 1000 # 自动提交offset时间间隔
group:
id: my-consumer-group
auto:
offset:
reset: latest # 最新位置消费(可选 earliest)
concurrency: 3 # 并发线程数
注意:
producer.servers
和 consumer.servers
通常是一样的(Kafka 集群地址)。
auto.offset.reset
:
latest
:只消费启动后新的消息
earliest
:从最早可用的消息开始消费(适合首次启动的消费者)
在你的消费者容器工厂上,加个 SeekToCurrentErrorHandler
,遇到异常能自动重试N次(否则Kafka默认抛出异常整个消费线程就挂掉了!)
private KafkaListenerContainerFactory> getConsumerFactory(boolean batchListener) {
ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(concurrency);
factory.setBatchListener(batchListener);
// 消息处理异常时重试配置(重要)
factory.setErrorHandler(new SeekToCurrentErrorHandler(
new FixedBackOff(5000L, 3) // 5秒重试一次,总共重试3次
));
return factory;
}
细节说明:
SeekToCurrentErrorHandler
会把这条消息重新投到消费队列中,不会丢失。
FixedBackOff(5000L, 3)
:表示每隔5秒重试一次,重试3次后如果还失败就记录error日志。
如果你想更极致一点,比如:重试 N 次还失败就发到 死信队列(DLQ) ,也可以配!
别直接 kafkaTemplate.send()
完就不管了,加一个Callback回调,拿到真正的发送成功 or 失败,做链路监控。
补充一下发送方法:
@Autowired
@Qualifier("kafkaTemplate")
private KafkaTemplate kafkaTemplate;
public void sendMessageWithCallback(String topic, String message) {
kafkaTemplate.send(topic, message).addCallback(
success -> {
if (success != null) {
System.out.println("发送成功!topic:" + success.getRecordMetadata().topic() +
" partition:" + success.getRecordMetadata().partition() +
" offset:" + success.getRecordMetadata().offset());
}
},
failure -> {
System.err.println("发送失败!原因:" + failure.getMessage());
}
);
}
说明:
success
可以拿到:topic、partition、offset,链路追踪好用!
failure
可以拿到异常信息,比如超时、网络问题、队列满等。
组件 |
细节 |
---|---|
Producer |
配置 ProducerFactory、KafkaTemplate,支持异步Callback |
Consumer |
配置 ConsumerFactory、ListenerContainerFactory,支持批量、逐条消费、异常重试 |
配置文件 |
application.yml统一管理 |
错误处理 |
加了 |
发送保障 |
生产者发送加回调,失败报警 |
你可以直接拿来实战用,真正可以扛流量的 Kafka 消费生产链路!
✅ 正常消费 →
❌ 消费失败 + 重试多次 →
还是失败 →
➡️ 将原消息投递到【死信Topic】(Dead Letter Topic)
➡️ 后续人工修复 or 自动补偿
getConsumerFactory
方法,加 DeadLetterPublishingRecoverer我们要替换掉原来的 SeekToCurrentErrorHandler
,换成支持死信队列的异常处理器:
@Autowired
@Qualifier("kafkaTemplate") // 用来发到死信topic
private KafkaTemplate kafkaTemplate;
private KafkaListenerContainerFactory> getConsumerFactory(boolean batchListener) {
ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(concurrency);
factory.setBatchListener(batchListener);
// 配置死信队列处理器
DeadLetterPublishingRecoverer recoverer = new DeadLetterPublishingRecoverer(kafkaTemplate,
(r, e) -> new TopicPartition(r.topic() + ".DLT", r.partition())
// 失败后投递到原Topic后缀加.DLT(Dead Letter Topic)
);
// 失败后重试3次,每次间隔5秒,重试完仍失败则交给recoverer处理
factory.setErrorHandler(new SeekToCurrentErrorHandler(recoverer, new FixedBackOff(5000L, 3)));
return factory;
}
解释一下:
DeadLetterPublishingRecoverer
:失败后自动把消息重新生产到 .DLT
结尾的新Topic,比如消费 order-event
失败了,就投到 order-event.DLT
FixedBackOff(5000, 3)
:5秒重试1次,总共重试3次
如果3次都失败,就触发 recoverer
,把消息扔到死信队列里。
Kafka死信队列是一个普通的Topic,只不过你最好提前建好(也可以用自动创建)。
比如:
kafka:
topics:
- name: order-event
- name: order-event.DLT # 死信队列
如果你用的 Kafka Server 开了自动建Topic(auto.create.topics.enable=true),也可以不手动建。
比如你可以新建一个 DLQ 处理器,专门监听死信消息:
@Component
public class DeadLetterConsumer {
@KafkaListener(topics = "order-event.DLT", groupId = "dead-letter-group")
public void consumeDeadLetter(String message) {
System.err.println("【死信消息处理】收到消息:" + message);
// TODO: 这里可以发告警、落库、人工介入、补偿逻辑等
}
}
注意:这里可以记录日志、发告警(钉钉/飞书/邮件),或者存到DB里,方便后续人工修复。
正常消费成功 --> 直接ack
正常消费失败 --> 重试 --> 成功ack
重试N次失败 --> DeadLetterPublishingRecoverer --> 投递到 死信Topic
死信消费者监听 --> 告警 or 补偿处理
步骤 |
内容 |
---|---|
1 |
给 KafkaListenerContainerFactory 加上 DeadLetterPublishingRecoverer |
2 |
配好死信Topic(一般就是正常Topic后加 |
3 |
写一个专门的死信消费者 |
4 |
死信消息可以告警、存库、人工补偿 |
这样配置下来,你的 Kafka 消费链路就非常稳定了:不会因为单条脏数据影响整体消费系统健康。
死信消息里最好加上:
原始消息体
消费失败原因(异常栈)
时间戳
死信消费可以打到链路追踪系统,比如接入 Skywalking/Zipkin
对重要消息类型可以设置死信消息补偿重试机制
Bean |
作用 |
---|---|
ServerEndpointExporter |
核心 !Spring Boot 启动时会扫描 |
BaseEndpointConfigure |
扩展配置 ,通常用来自定义 WebSocket 握手过程,比如:校验token、设置自定义属性、统一Session管理、拦截器(handshake拦截)等。 |
Spring Boot 容器启动 →
扫描到 @Configuration
注解的 WebSocketConfig
→
创建 ServerEndpointExporter
实例,注册到 Spring 容器中 →
ServerEndpointExporter
开始扫描项目中所有 @ServerEndpoint
注解的类 →
找到后,自动将这些类注册成 WebSocket端点(endpoint) →
创建 BaseEndpointConfigure
Bean,供你后续扩展(比如你可以写自己的 modifyHandshake
)