RabbitMQ 重复消费问题:最通俗易懂的解决方案(幂等性)+ 实战总结
2026/4/16 12:26:43 网站建设 项目流程

RabbitMQ 重复消费问题:最通俗易懂的解决方案(幂等性)+ 实战总结

    • 一、为什么会出现重复消费?
    • 二、核心解决思路:实现**幂等性**
    • 三、最常用、最稳定的 3 种解决方案(工作必用)
      • 方案1:唯一ID + Redis 分布式锁(生产 90% 场景用这个)
      • 方案2:数据库唯一索引(简单业务)
      • 方案3:状态机判断(订单/支付最常用)
    • 四、三种方案对比(直接背)
    • 五、最重要的 3 条规则(必须记住)
    • 六、一句话总结(面试标准答案)

🌺The Begin🌺点点关注,收藏不迷路🌺

一、为什么会出现重复消费?

RabbitMQ无法保证消息只发一次,只能保证至少发一次

出现重复消费的常见原因:

  1. 消费者处理完业务,但没来得及 ACK,连接断了
  2. 消费者异常、重启、超时
  3. MQ 重试、重入队
  4. 生产者重试发送

结果:同一条消息被消费多次


二、核心解决思路:实现幂等性

什么是幂等?
同一个消息执行多次,结果只生效一次,不会重复扣钱、重复下单。


三、最常用、最稳定的 3 种解决方案(工作必用)

方案1:唯一ID + Redis 分布式锁(生产 90% 场景用这个)

原理:

  • 每条消息带一个全局唯一ID(msgId / orderId)
  • 消费者先去 Redis加锁
  • 加锁成功 → 消费
  • 加锁失败 → 说明已经消费过,直接跳过

流程图:

收到消息 → 取唯一ID → Redis加锁 → 加锁成功:执行业务 → ACK → 加锁失败:直接ACK,不处理

核心代码(简化版):

// 1. 先拿消息唯一IDStringmsgId=message.getMessageProperties().getMessageId();// 2. Redis 加锁(不存在才设置)Booleanlock=redisTemplate.opsForValue().setIfAbsent("lock:"+msgId,"1",10,TimeUnit.MINUTES);if(lock==null||!lock){// 重复消息,直接确认,不处理channel.basicAck(tag,false);return;}// 3. 正常执行业务// ...// 4. 确认消息channel.basicAck(tag,false);

方案2:数据库唯一索引(简单业务)

适用:插入数据、记录日志
给业务表的唯一字段(如 orderId)加唯一索引

重复插入会报唯一键冲突,捕获后直接 ACK 即可。


方案3:状态机判断(订单/支付最常用)

适用:订单、支付、物流等状态流转

比如订单状态:
1=待支付 → 2=已支付

消费时执行:

UPDATEorderSETstatus=2WHEREid=?ANDstatus=1;
  • 更新行数=0 → 已经处理过,直接跳过
  • 更新行数=1 → 正常处理

天然幂等!


四、三种方案对比(直接背)

方案适用场景性能推荐度
Redis 分布式锁所有业务(最强通用)极高⭐⭐⭐⭐⭐
数据库唯一索引插入类数据良好⭐⭐⭐
状态机更新订单/支付/状态流极高⭐⭐⭐⭐⭐

五、最重要的 3 条规则(必须记住)

  1. 重复消费无法避免,只能靠消费端做幂等!
  2. 必须使用手动 ACK
  3. 先判断幂等,再执行业务

六、一句话总结(面试标准答案)

RabbitMQ 重复消费无法避免,解决方法是实现消费端幂等
最常用方案是全局唯一ID + Redis 分布式锁,确保一条消息只消费一次;
订单类业务可使用状态机更新实现天然幂等。



🌺The End🌺点点关注,收藏不迷路🌺

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询