1、解决消息丢失的第一个问题:订单系统推送消息领丢失
既然我们已经明确了消息在基于MQ传输的过程中可能丢失的几个地方,那么我们接着就得一步一步考虑如何去解决各个环节丢失消息的问题,首先要解决的第一个问题,就是订单系统推送消息到MQ的过程中,可能消息就丢失了。
之前我们也说过了,可能在订单系统推送消息到MQ的过程中,就因为常见的网络故障之类的问题,导致消息就丢失了,这里我们可以看一下下图中的示意。
而在RocketMQ中,有一个非常强悍有力的功能,就是事务消息的功能,凭借这个事务级的消息机制,就可以让我们确保订单系统推送给出去的消息一定会成功写入MQ里,绝对不会半路就搞丢了。
今天我们就来系统的分析一下RocketMQ的事务消息机制的原理。
2、发送half消息到MQ去,试探一下MQ是否正常
首先作为我们的订单系统而言,假设他收到了一个订单支付成功的通知之后,他必然是需要在自己的订单数据库里做一些增删改操作的,比如更新订单状态之类的。
可能有的朋友会觉得,订单系统不就是先在自己数据库里做一些增删改操作,然后就直接发个消息到MQ去,让其他关注这个订单支付成功消息的系统去从MQ获取消息做对应的处理就可以了么?
事实上还真不是这么简单。
在基于RocketMQ的事务消息机制中,我们首先要让订单系统去发送一条half消息到MQ去,这个half消息本质就是一个订单支付成功的消息,只不过你可以理解为他这个消息的状态是half状态,这个时候红包系统是看不见这个half消息的,然后我们去等待接收这个half消息写入成功的响应通知
我们看下面的图
看到这儿可能有的朋友就开始有点郁闷了,可能有的人觉得你没事儿先发个half消息给MQ干什么?
大家先别着急,你可以想一下,假设你二话不说让订单系统直接做了本地的数据库操作,比如订单状态都更新为了已完成,然后你再发送消息给MQ,结果报出一堆异常,发现MQ挂了。
这个时候,必然导致你没法通过消息通知到红包系统去派发红包,那用户一定会发现自己订单支付了,结果红包没收到。
所以,在这里我们首先第一件事,不是先让订单系统做一些增删改操作,而是先发一个half消息给MQ以及收到他的成功的响应,初步先跟MQ做个联系和沟通
大概这个意思就是说,确认一下MQ还活着,MQ也知道你后续可能想发送一条很关键的不希望丢失的消息给他了!
3、万一要是half消息写入失败了呢?
这里我们先来分析第一种情况,万一你订单系统写half消息给MQ就失败了呢?
可能你发现报错了,可能MQ就挂了,或者这个时候网络就是故障了,所以导致你的half消息都没发送成功,总之你现在肯定没法跟MQ通信了。
这个时候你的订单系统就应该执行一系列的回滚操作,比如对订单状态做一个更新,让状态变成“关闭交易”,同时通知支付系统自动进行退款,这才是正确的做法
因为你订单虽然支付了,但是包括派发红包、发送优惠券之类的后续操作是无法执行的,所以此时必然应该把钱款退还给用户,说交易失败了。
这里给大家插播一个我曾经亲身经历过的一个事情,曾经有一次在一家便利店进行购物的时候,我这里都已经显示扫码支付成功了,但是店员那边说在等待他们系统确认
结果等了一会儿,系统显示后台系统有异常,交易失败了,然后过了一会儿就让支付宝自动退款给我了。
其实这就是类似的例子。