跳至主要內容

12.MQ重复消费问题如何解决?

Java突击队大约 4 分钟

12.MQ重复消费问题如何解决?

前言

之前MQ带来的一些问题,我已经分享了很多了,比如:消息顺序问题、消息积压问题、消息丢失问题等等。

今天接着MQ带来的问题这个话题,专门跟大家一起聊聊MQ消息重复消费的问题。

点击这里:商城系统实战、秒杀系统实战、代码生成工具实战、工作经验分享、技术选型、系统设计、性能优化、源码解读、高频面试题,这里什么都有

1 MQ消息为什么会重复消费?

下面用一张图概况一下MQ的整体架构:

MQ的整体架构中,需要3种角色:

  1. MQ生产者:负责生成MQ消息。
  2. MQ服务器:负责保存MQ消息。
  3. MQ消费者:负责消费MQ消息。

在一个完整的MQ业务场景中,这3种角色缺一不可。

1.1 MQ生产者

MQ生产者如果没有做消息是否已经发送判断,可能会产生重复的消息。

这样会导致MQ消费者消费重复的消息。

1.2 MQ服务器

MQ服务器接收到MQ消息之后,写入磁盘文件成功,但是写入offset失败了。

MQ服务器挂了,重启之后,offset可能会丢失5秒钟左右的offset数据。

这时候MQ消费者消费MQ时,使用的可能还是老的offset,造成同一条消息被消费多次的问题。

1.3 MQ消费者

MQ消费者消费到重复消息的场景比较多。

比如:我们的MQ消费者在消费了MQ消息之后,没有自动确认,而是接着处理业务逻辑。

如果处理成功,则手动确认消息。

如果处理失败,则直接抛了异常。

由于没有确认,offet没有变化,下次MQ消费者,还能继续消费这条消息。

还有这种情况:比如MQ消费者出现了一个非常严重的BUG,导致一大批消息都没有正确被处理。

这时候可能会将offset回退到某一个值,重放之前消费过的消息。

这些场景都会导致MQ消息被重复消费。

那么,如果防止MQ重复消费带来的问题呢?

2 如何解决重复消费问题?

其实,我在实际工作中,遇到过太多次,MQ消息被重复消息的问题。

因此,在我们的MQ消费者中,一定要做好幂等性设计。

也就是:同一条MQ消息,在MQ消费者中允许被重复消费多次,但不影响正常的业务逻辑。

RocketMQ的官方文档中提到过:RocketMQ确保所有消息至少传递一次。MQ消息在大多数情况下,不会重复。

也就是说:有少部分MQ消息会重复。

要完全避免MQ消息不重复,非常非常难。

我们优先在MQ消费者中,做好幂等性设计。

以用户下单为例:

  1. 判断订单是否存在,如果已存在,则直接返回该订单数据。
  2. 如果不存在,则下单,返回订单数据。

当然为了保险起见,可以在表中给订单编号增加唯一索引。

这个订单编号是在前端跳转到下单页面,根据一定的规则,调用服务端的接口提前生成好的。

这样设计之后,即使MQ消息被重复消费多次,也不会影响业务流程。

同时,我们的MQ生产者中,也要增加是否已成功发送MQ消息的判断逻辑。

如果已经发送,则无需重复发送。

可以根据业务表的数据来做判断。

此外,我们也要严格控制MQ重复消费的次数,特别是在MQ消费者中消费消息失败抛异常,触发重试机制时。

需要设置一个阀值,比如:3次。

如果MQ消费者在消费消息时,处理失败了,重试3次之后还是失败,则将该消息发送到死信队列。

该MQ消费者不再消费这条消息了。

后续需要人工介入。

当然我们需要有一个程序,专门监控死信队列的数据变化,一旦有数据时,发报警邮件通知相关开发人员。

为了帮助更多的粉丝朋友,找到个好工作,多拿几个offer。苏三最近建一些工作内推群,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。