如何防止 Kafka 消息在提交过程中丢失?Spring Boot 实战指南

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!


一、问题背景:消息为什么会"丢"?

很多开发者以为 Kafka "天生可靠",但消息丢失往往发生在"消费端提交偏移量"的环节

即使 Kafka 本身持久化了消息,如果你的消费者提前提交了 offset ,而业务逻辑还没执行完,一旦应用崩溃------这条消息就永远消失了

🎯 典型场景:

  • 用户下单成功,Kafka 发送"订单创建"事件
  • 消费者收到消息,准备扣库存
  • offset 被提前提交
  • 扣库存前服务宕机 → 订单已确认,但库存没扣!

这不是 Kafka 的锅,而是提交策略不当导致的!


二、根本原则:先处理业务,再提交 offset

正确顺序

复制代码
1. 拉取消息
2. 执行业务逻辑(如写 DB、调接口)
3. 业务成功 → 提交 offset

错误顺序(自动提交默认行为)

复制代码
1. 拉取消息
2. 后台线程定时提交 offset(不管业务是否完成)
3. 业务执行中崩溃 → 消息丢失

三、解决方案:关闭自动提交 + 手动 ACK + 幂等消费

下面我们用 Spring Boot + Kafka 实现一个不丢消息的消费者。


✅ 步骤 1:关闭自动提交(关键!)

复制代码
# application.yml
spring:
  kafka:
    consumer:
      enable-auto-commit: false     # 必须关闭!
      group-id: order-service
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-desserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring.json.trusted.packages: "com.example.dto"

⚠️ enable-auto-commit: false 是防止消息丢失的第一道防线!


✅ 步骤 2:配置手动 ACK 模式

复制代码
// KafkaConfig.java
@Configuration
@EnableKafka
public class KafkaConfig {

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, OrderEvent> kafkaListenerContainerFactory(
            ConsumerFactory<String, OrderEvent> consumerFactory) {
        ConcurrentKafkaListenerContainerFactory<String, OrderEvent> factory =
                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory);
        // 设置为手动立即确认
        factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
        return factory;
    }
}

✅ 步骤 3:消费者代码:业务成功才 ACK

复制代码
// OrderConsumer.java
@Component
public class OrderConsumer {

    @Autowired
    private InventoryService inventoryService;

    @KafkaListener(topics = "order-created", groupId = "order-service")
    public void consume(OrderEvent event, Acknowledgment ack) {
        try {
            // 1. 业务处理:扣减库存
            inventoryService.decreaseStock(event.getProductId(), event.getQuantity());

            // 2. 业务成功 → 手动提交 offset
            ack.acknowledge(); 

            log.info("订单 {} 处理成功,offset 已提交", event.getOrderId());

        } catch (Exception e) {
            // 3. 业务失败 → 不提交 offset!
            log.error("处理订单失败,不提交 offset,等待重试", e);
            // 可选:记录到死信队列,避免无限重试
        }
    }
}

✅ 这样:只有库存扣减成功,offset 才会提交。如果失败,下次重启还会重新消费同一条消息。


四、进阶保障:幂等性设计(防重复消费)

由于我们采用"失败不提交 offset",消息可能会被重复消费 。因此,消费者必须幂等

🔧 幂等实现方式:

方式 1:数据库唯一索引(推荐)
复制代码
CREATE TABLE processed_messages (
    message_id VARCHAR(64) PRIMARY KEY,  -- Kafka 消息的 key 或生成的 UUID
    processed_at TIMESTAMP
);

消费时:

复制代码
if (!messageLogService.exists(event.getMessageId())) {
    // 执行业务
    inventoryService.decreaseStock(...);
    // 记录已处理
    messageLogService.save(event.getMessageId());
    ack.acknowledge();
}
方式 2:业务状态机
  • 订单状态:CREATEDSTOCK_DEDUCTED
  • 如果已经是 STOCK_DEDUCTED,直接跳过

五、反例对比:自动提交 vs 手动提交

场景 自动提交(enable-auto-commit=true) 手动提交(enable-auto-commit=false)
消费消息后处理耗时 10 秒 5 秒时自动提交 offset 不提交,直到 ack.acknowledge()
处理到第 8 秒时服务崩溃 消息丢失(offset 已提交) 消息保留(offset 未提交,重启后重试)
适合场景 日志、监控等可容忍丢失的数据 订单、支付、通知等关键业务

六、其他注意事项

1. 不要在 ACK 后做关键操作

复制代码
// ❌ 危险!ACK 后再操作,崩溃会导致数据不一致
ack.acknowledge();
inventoryService.decreaseStock(...); // 崩溃 → offset 提交了,但库存没扣!

✅ 正确顺序:业务 → ACK


2. 避免长时间阻塞消费者线程

  • 如果业务耗时很长(如调外部 API),考虑异步处理 + 本地事务表
  • 或使用 @RetryableTopic + 死信队列(DLQ)机制

3. 测试你的容错能力

  • kill -9 模拟非优雅关闭
  • 观察消息是否重试、是否重复、是否丢失

七、总结

要防止 Kafka 消息在提交过程中丢失,请牢记:

  1. 关闭自动提交enable-auto-commit: false
  2. 业务成功后再手动 ACK
  3. 消费者必须幂等(防重复)
  4. ACK 前不要做任何可能失败的关键操作

这样,即使服务崩溃、网络中断、机器宕机,你的消息也不会丢失!

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

相关推荐
linux修理工1 天前
使用codebuddy学习kafka
分布式·学习·kafka
开开心心就好1 天前
解决截图被拦截黑屏问题的免费小工具
安全·智能手机·flink·kafka·pdf·音视频·1024程序员节
linux修理工2 天前
kafka积压
数据库·分布式·kafka
杰克逊的日记2 天前
kafka消息堆积了怎么处理
大数据·分布式·kafka
linux修理工2 天前
使用codebuddy调优kafka等
分布式·kafka
functionflux2 天前
kafka-python:Python 生态中最成熟的 Kafka 客户端
分布式·python·其他·kafka
q21030633722 天前
kafka启动几秒后挂了,重启多次无果
分布式·kafka
abcy0712133 天前
在Python 中使用Celery和Kafka进行消息队列的生产者和消费者实现
python·kafka
阿坤带你走近大数据3 天前
如何保证kafka中的数据一致性
分布式·kafka
阿坤带你走近大数据3 天前
Kafka中的分区概念
分布式·kafka