【RabbitMQ】高级使用:补偿机制、消息幂等性、最终一致性、消息顺序性

1.补偿机制

由于生产者与消费者完全隔离,即使消费者没有接收到消息,或者消费时出现异常,生产者也是完全不知情的。所以生产者最终确定消费者有没有消费成功有两种通信方式:

  1. 消费者收到消息,处理完毕后,调用生产者的API

    例如:提单系统给其他系统发送了碎屏保消息后,其他系统必须在处理完消息后调用提单系统提供的API,来修改提单系统中数据的状态。只要API没有被调用,数据状态没有被修改,提单系统就认为下游系统没有收到这条消息。

  2. 消费者收到消息,处理完毕后,发送一条响应消息给生产者

    例如:商业银行与人民银行二代支付通信,无论是人行收到了商业银行的消息,还是商业银行收到了人行的消息,都必须发送一条响应消息(叫做回执报文)。

【RabbitMQ】高级使用:补偿机制、消息幂等性、最终一致性、消息顺序性
无论采用哪种回调方式,如果生产者的API就是没有被调用,也没有收到消费者的响应消息,怎么办?可能是消费者处理时间太长或者网络超时。

生产者与消费者之间应该约定一个超时时间,比如5分钟,对于超出这个时间没有得到响应的消息,可以设置一个定时重发的机制

  • 重发可以通过消息落库+定时任务来实现

  • 要控制发送间隔和次数,比如每隔2分钟发送一次,最多重发3次,否则会造成消息堆积

  • 重发的消息,随具体场景的变化而变化,不能在Producer写死

    参考:ATM机上运行的系统叫C端(ATMC)。前置系统叫P端(ATMC),它接收ATMC的消息,再转发给卡系统或者核心系统。

    • 如果客户存款,没有收到核心系统的应答,不知道有没有记账成功,最多发送5次存款确认报文,因为已经吞钞了,所以要保证成功;
    • 如果客户取款,ATMC未得到应答时,最多发送5次存款冲正报文。因为没有吐钞,所以要保证失败。

2.消息幂等性

如果消费者每一次接收生产者的消息都成功了,只是在响应或者调用API的时候出了问题,会不会出现消息的重复处理?例如:存款100元,ATM重发了5次,核心系统一共处理了6次,余额增加了600元。

所以幂等性简单来说就是:重复调用多次产生的业务结果与调用一次产生的业务结果相同;

为了避免相同消息的重复处理,必须要采取一定的措施。RabbitMQ服务端是没有这种控制的(同一批的消息有个递增的DeliveryTag),它不知道你是不是就要把一条消息发送两次,只能在消费端控制。

如何避免消息的重复消费?消息出现重复可能会有两个原因:

  1. 生产者问题,环节①重复发送消息,比如在开启了Confirm模式但未收到确认,生产者重新发送消息
  2. 消费者问题,环节④出了问题,由于消费者未发送ACK或者其他原因,消息重复投递

对于重复发送的消息,可以对每一条消息生成一个唯一的业务ID,通过日志或者消息落库来做重复控制。

3.最终一致性

如果确实是消费者宕机了,或者代码出现了BUG导致无法正常消费,在我们尝试多次重发以后,消息最终也没有得到处理,怎么办?

例如存款的场景,客户的钱已经被吞了,但是余额没有增加,这个时候银行出现了长款,应该怎么处理?如果客户没有主动通知银行,这个问题是怎么发现的?银行最终怎么把这个账务做平?

在我们的金融系统中,都会有双方对账或者多方对账的操作,通常是在一天的业务结束之后,第二天营业之前。我们会约定一个标准,比如ATM跟核心系统对账,肯定是以核心系统为准。ATMC获取到核心的对账文件,然后解析,登记成数据,然后跟自己记录的流水比较,找出核心有ATM没有,或者ATM有核心没有,或者两边都有但是金额不一致的数据。

对账之后,我们再手工平账。比如取款记了账但是没吐钞的,做一笔冲正。存款吞了钞没记账的,要么把钱退给客户,要么补一笔账

4.消息顺序性

消息的顺序性指的是消费者消费消息的顺序跟生产者生产消息的顺序是一致的。示例如下

  • 商户信息同步到其他系统,有三个业务操作:1、新增门店 2、绑定产品 3、**门店,这种情况下消息消费顺序不能颠倒(门店不存在时无法绑定产品和**)。
  • 1、发表微博;2、发表评论;3、删除微博。顺序不能颠倒。

在RabbitMQ中,一个队列有多个消费者时,由于不同的消费者消费消息的速度是不一样的,顺序无法保证。只有一个队列仅有一个消费者的情况才能保证顺序消费(不同的业务消息发送到不同的专用的队列)。

【RabbitMQ】高级使用:补偿机制、消息幂等性、最终一致性、消息顺序性

==> 除非负载的场景,一个队列不要用多个消费者消费消息。