Skip to Content
面试题库Message Queue[面试题] 重复消费问题有可能是什么原因导致的?如何保证不重复消费?

[面试题] 重复消费问题有可能是什么原因导致的?如何保证不重复消费?

📖 版块 A:知识讲解版 (温故知新)

产生原因

  1. 生产者重发:网络抖动导致生产者没收到Broker的ACK,触发重发,Broker存了两条。
  2. 消费者重投:消费者处理完业务,但在给Broker发提交位点(Offset/ACK)时网络超时,Broker以为没消费,重新投递。
  3. 触发重平衡(Rebalance):消费组加减机器导致队列重新分配,部分未异步提交位点的消息被新接手的机器重复拉取。

防重复的核心:MQ底层只保证“At least once(至少一次)”,防重的责任在业务消费端。

幂等性解决方案

  1. 最关键的肯定是在接口层面就要保证幂等性
  2. 强校验:利用数据库唯一索引(如订单号做主键插入流水表)。
  3. 弱校验:利用唯一业务字段去进行判断,最简单的,秒杀业务中的分布式锁,这个就是一个业务字段,使用的一般是user_id。
  4. 状态机:利用业务状态扭转(如只有“未支付”才能改成“已支付”)。

🎤 版块 B:面试实战版 (高手逐字稿)

Q:如果发生重复消费,可能是什么原因导致的?如何保证不重复消费?

🧠 破局思路:先为MQ开脱,说明分布式系统下重复投递是不可避免的(At least once),然后抛出唯一的解法:在消费端实现幂等性。

💬 高手逐字稿: 遇到重复消费,我们要知道这是分布式网络环境下不可避免的必然现象。无论是生产者没收到ACK导致的重发,还是消费者提交Offset时网络超时,亦或者是消费集群触发了Rebalance,都会导致消息被重复投递。MQ中间件为了追求极高吞吐,它的底线是保证“At least once(至少消费一次)”,把防重复的包袱丢给了我们业务端。

所以在工程实践中,我们必须在消费逻辑里实现“幂等性”。最稳妥的办法就是“防重表+唯一索引”。以订单消息为例,我们取出消息里的订单号,在执行核心业务前,先往一张防重表里插入这笔订单号(字段建唯一索引)。如果是重复消息,数据库会报唯一键冲突(DuplicateKeyException),我们捕获这个异常直接当做消费成功返回给MQ即可。如果是并发要求极高的场景,我会改用Redis的 setnx 或者结合业务实体自带的状态机机制去实现防重。

最后更新于:
⏱️

登录后开始阅读

当前 MVP 版本只开放邮箱密码登录注册。完成登录后即可进入面试题内容。

还没有账号?先去注册