如何保证mq消息的幂等性

由于mq是为了系统之间的解耦,很好的解除了订阅者、发布者之间的耦合。
当mq中的消息发布的时候,如果发布失败,返回非200,或者超时,则直接进行重试的机制,不断的重试。所以目前线上经常有消费者因为代码有问题后,mq的报警就不断,一直fatal。
因为mq的重试机制,所以我们需要考虑消息的幂等性。

一、问题:如何保证mq消息幂等性

eg:用户下单后,需要把用户的下单的行为记录下来,然后通过mq发送给下游进行统计。

1.1、传统的mq方式


步骤

  • 1、client发布端把用户下单的行为发布到mq中
  • 2、mq主动把用户行为推送给接收端

问题

  • 如果1步骤超时重试了,那么mq会重复接收,并重复发送给client接收端。
  • 如果2步骤超时重试了,那么mq也会重试。client则会进行多次调用。
  • 如果步骤2被多次调用,会导致用户下单被多次记录。

假设这里每个消息需要一个全场的唯一id。比如订单系统中有订单id。

二、解决方法一:

  • 每次发布的时候,把order_id存入set集合。
  • 接收端接收到消息后,判断order_id存不存在redis。存在则继续执行,并删除;不存在则直接return
  • 第1步超时的情况下,client接收端发现set集合中没有order_id则不处理;
  • 第2步超时的情况下,接收端中的set集合中的order_id已经被处理了,发现已经没有orderId也不处理;

    2.1、缺点

  • 1、发布端与接收端没有真正意义上的完全解耦,还是有关联,幂等性应该由接收端来保证,发布端不关心。
  • 2、如果发布端有效率上的严格要求话,每次需要增加redis的写入操作

关于这个方法,有一种别的类似方法传送门

三、解决方法二:

  • 发布的时候,没有别的操作,只管发布,上半场不控幂等。
  • 接收的时候,需要setnex order_id的操作。如果为1,那么就代表这个消息第一次接收;如果为0,则代表已经接收过消息
  • redis的key需要设置过期时间

3.1、缺点

  • 1、因为每有一个订单,都需要往redis去set,所以订单量大的时候会导致数据量很大。

选择什么解决方法,需要对业务观察,选择一个符合业务的,毕竟脱离业务的架构都是刷流氓

文章目录
  1. 1. 一、问题:如何保证mq消息幂等性
    1. 1.0.1. 1.1、传统的mq方式
  • 2. 二、解决方法一:
    1. 2.0.1. 2.1、缺点
  • 3. 三、解决方法二:
    1. 3.0.1. 3.1、缺点
  • ,