200520-MQ重复消费问题解决方案

MQ重复消费问题解决方案

正常消息处理过程

MQ_MSG_PROCESS

重复消费如何产生

原因一(生产者)

  1. 生产者发送给消息队列以后,消息队列会响应给生产者,但是这个过程中,消息队列出问题了没有收到消息,那么生产者就会重复发生消息,这时就产生了重复消息。(消息服务器本身逻辑异常)
  2. 生产者发生消息给消息队列,消息队列由于数量太大延迟了,生产者等待响应超时了,这时生产者又会从新发生消息给消息队列。(消息队列响应超时)
  3. 生产者和消息队列因网络问题引起,生产者会发起重试。这样也会产生重复消息。 (网络问题)

其实主要原因就是,消息成功进入了消息队列,但是由于各种原因消息队列没有给生产者成功的返回值,而生产者又有重试机制这种情况下就会产生重复消息。

原因二 (消费者)

  1. 消息队列推送给消费者,消费者处理消息这个过程中消费出现了问题,消息队列不知道消费者处理结果,就会在次投递。(消费者本身问题)
  2. 消费者处理完,网络出现问题,这时没有给中间件消息队列返回结果,消息队列会在次投递消费者。(网络问题)
  3. 消费者处理超时,超过了消息队列的超时时间,这时消息队列也会再次投递。(消费处理超时)
  4. 消费者处理完结果返回给消息中间件,但是消息中间件出现问题,处理结果丢失了,重启后,消息中间件内部检查发现这个消息还没有处理也会在次投递给消费者。

解决重复消息幂等性操作

幂等性举例说明

  1. 语句一:update table_a set count = 10 where id = 1;
  2. 语句二:update table_a set count = count + 1 where id = 1;

语句一无论修改多少次count永远是10,这个操作就可以说是幂等的;语句二每次修改count会加1,那么这个操作就可以说非幂等的。

解决方式

  1. 数据库唯一主键
    消息是做数据库的插入操作,给这个消息做一个唯一主键,那么就算出现重复消费情况,就会导致主键冲突,避免数据库出现脏数据。
  2. 推荐 redis
    给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。消费者开始消费之前,先去redis中查询有没有消费记录即可。存储方式可以例如 MQ的ID作为Key,常用的UUID作为value.或者调换过来也可以。

参考资料

#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×