MQ消息重复解决方案
兄弟们,面试被问“MQ消息重复消费怎么破?”是不是很头大?别慌!作为踩过坑的老码农,今天用大白话拆解几个超实用的解决方案,保你在面试官面前侃侃而谈!

📁 2025年Java面试宝典重磅资源:
👉点我速取《2025 Java面试高频宝典》👈
提取码: 9b3g (建议保存备用,涵盖MQ、分布式等硬核知识点!)
🔍 为什么MQ消息会重复?
先搞懂原因才能对症下药!消息重复通常发生在:
- 生产者重试:消息发送失败时自动重发(比如网络抖动)
- 消费端超时:消费者处理太久,MQ以为宕机了,把消息转给其他消费者
- Rebalance:消费者集群扩容缩容时,分区重新分配导致消息重复投递
🛡️ 解决方案一:消息去重表(最常用)
核心逻辑:利用DB主键唯一性拦截重复消息
CREATE TABLE msg_idempotent (
id VARCHAR(64) PRIMARY KEY, -- 消息唯一ID
status TINYINT DEFAULT 0, -- 0未处理/1已处理
create_time DATETIME
);
处理流程:
- 消费者接到消息后,先拿
msg_id查去重表 - 若记录存在且
status=1→ 直接ACK(说明已处理过) - 若记录不存在 → 插入数据并执行业务逻辑
- 业务完成后更新
status=1→ 提交ACK
适用场景: 数据库操作类业务(订单支付、库存扣减)
⚡ 方案二:业务逻辑幂等设计
关键:让相同参数的操作执行多次 = 执行一次
常见套路:
- 数据库唯一索引:订单ID+操作类型建唯一索引,重复插入直接报错
- 乐观锁机制:更新数据时带上版本号(version)
update account set balance=balance-100, version=version+1 where user_id=1 and version=10; - 状态机控制:订单从"已支付"→"已完成" 只能发生一次,重复流转直接拒绝

🧩 方案三:消费端过滤(缓存方案)
适合消息量大、时效性高的场景
// 伪代码示例:用Redis做去重缓存
String msgId = message.getId();
if(redis.setnx(msgId, "1", 24*3600)) { // 不存在才set
processMessage(); // 业务处理
redis.del(msgId); // 可选:防止长期占用内存
} else {
log.warn("重复消息:{}", msgId);
}
注意点:
- 缓存过期时间要大于业务最大处理时间
- 考虑Redis集群高可用(防止节点宕机导致穿透)
💡 面试加分技巧
当面试官追问时,可以这么聊:
“具体方案选择要看业务场景!比如对账系统用消息去重表更稳妥,秒杀库存用Redis去重更高效。另外大厂现在流行用 RocketMQ的幂等Producer 或 Kafka的Exactly-Once语义,但要注意性能损耗...”
🎁 福利时间
刷面试题没方向?强烈推荐 面试鸭返利网 的题库会员!
✅ 涵盖BATJ等大厂真题
✅ 技术点按频次排序
✅ 通过本站购买会员可返利25元!
👉 点击直达活动页 👈

最后划重点:
消息重复不可怕,关键是要在业务层做好兜底。搞懂上面3招,面试官都得给你竖大拇指! 🚀


