3.如何保证消息不被重复消费?
一、问题引导思维
- 使用 MQ(消息队列)时,是否考虑过消费端可能会 重复处理一条消息?
- 如何判断一条消息是否已经消费过?
- 如果重复消费不可避免,该如何设计业务逻辑保证 幂等性?
面试官心理:你不仅要知道 MQ 会出现重复消费的场景,更要知道如何设计“幂等的消费逻辑”,这体现你对架构鲁棒性的理解和实践能力。
二、为什么会重复消费?(通俗解释)
消息队列在实际使用过程中重复消费是常态,不是异常。
以 Kafka 为例:
- 消费者从 Kafka 拿到一条消息,先处理再提交 offset。
- 如果处理完成后还没来得及提交 offset 就宕机了,那么offset 没更新,下一次启动还是会从旧 offset 开始读,之前处理过的消息就会再来一次。
生活类比:
- 你吃饭前记得拍个照(提交 offset),结果照片没拍就断电了,朋友再让你拍时,只能从上一顿饭重来,饭你是吃过了,但别人不知道。
三、如何解决重复消费问题?(思路 + 实践)
重复消费不可怕,关键是保证幂等性 —— 相同的消息消费多次不会影响最终结果。
常见解决方案:
| 场景 | 解决方案 | 幂等性实现思路 |
|---|---|---|
| 数据库写入操作 | 使用唯一索引或幂等判断 | 主键或唯一字段控制重复插入 |
| Redis 写数据 | 使用 SET 或 SETNX 命令 |
SET 覆盖,SETNX 只设置一次 |
| 有业务 ID(如订单号) | 消息体中携带唯一 msgId、orderId 等 |
消费前查 Redis 或 DB 判断是否处理过 |
| HTTP/接口幂等 | 提供 token 或请求唯一标识,避免重复提交 | 中间件记录标识处理状态 |
| 状态机类操作(如扣库存) | 记录“幂等日志”或“操作流水”,控制状态变更幂等 | 判断之前状态是否已变更 |
四、为什么 MQ 本身不负责幂等性?
因为 MQ 的设计原则是:
- 尽最大努力送达消息(不丢)
- 允许少量重复投递
- 幂等性是 业务层 的责任,每个业务场景都不一样,MQ 没法一刀切处理
五、不同 MQ 的重复消费特点
| MQ 类型 | 是否可能重复投递 | 原因说明 |
|---|---|---|
| Kafka | ✅ | offset 提交机制存在延迟,处理成功但 offset 未提交 |
| RabbitMQ | ✅ | 使用 at-least-once 模式,可能重新投递 |
| RocketMQ | ✅ | 支持重试机制,失败后会再次投递消息 |
六、选型建议(面对重复消息的处理)
| 场景 | 建议 |
|---|---|
| 高性能系统,写入频繁 | Redis 结构天然幂等,适合做幂等去重记录 |
| 强一致性需求,事务敏感 | 数据库唯一索引 + 幂等判断逻辑 |
| 分布式订单、库存系统 | 携带业务唯一 ID,并结合幂等日志或流水进行判断处理 |
| 批量消费消息 | 持久化消费日志,定期清理已处理 ID |
| 多实例并发消费 | Redis + 分布式锁控制并发幂等消费 |
七、一句话总结
重复消费是消息队列的正常现象,关键在于你有没有设计幂等逻辑,确保系统的数据不会因为重复处理而“翻车”。

浙公网安备 33010602011771号