在介绍方案之前,我带着大家回顾一下之前我简化完的支付系统,以及支付系统中出现的分布式事务的问题。
在3rd-access成功更新订单,但是通知商户因为网络或者商户服务宕机的原因,没有通知成功step6,这时候会带来订单数据的丢失,导致商户那边明明扣了钱,但是得不到不到权益,下面我们就针对这种情况,一起探讨下解决方案。
为了更好的探讨这个问题,我们将系统的其他服务暂时先抛弃,针对step6进行一个分析。如图
针对step6,通常我们会用一个http请求的方式去通知商户。但是http是无状态协议,通知一次失败了就失败了,所以我们在想是否能够做成重复通知的情况,如果没有通知就每隔多少时间再通知一次。但是又不是无限的通知下去,一次又一个最大的通知次数。但是,如果这个数据很重要,在到达最大通知次数之后我们不再通知了,但是商户现在又修复好了服务,让我重新通知一次,那我们又该如何处理那,下面来看改造之后的方案。如图:
红线部分是老的通知方案,其他最大努力通知的方案。
- 支付宝支付回调成功结果
- 3rd-access(更新订单,并把结果丢到消息服务Mq),这两步在同一个本地事务中进行,保证了一致性。
- 通知服务可以成一个监听服务,监听到mq里面有新的消息,马上取出来(状态为"消费中")保存到通知库,并且通知商户,这个过程也在本地事务进行,保证数据的一致性
- 商户响应接收成功,通知服务会删除mq里面的消息(更改消息为"消费成功")
这样保证了正向流程的消息一致性。
那么针对异常流程,是否会造成消息的丢失呢?我们来看下情况
- 在此我们默认订单是更新成功的(这里会在第二套方案里面讲),因为消息服务是高可用架构,所以宕机的可能性不大,而且更新订单和丢数据到mq是同一个事物,要么全部成功,要么全部失败,所以订单更新成功的,该消息一定成功的丢到了mq里面,并且为了保证数据一致性,该消息是一定要被消费而且通知给商户的。
- 如果通知服务有问题,那么消息只是没有被消费而已,还是一直存在消息服务里面的,所以一旦通知服务恢复正常,消息还是能被消费的,这里并不会导致消息的丢失。
- 通知消息入库有问题,那么这里会抛出异常,但是因为只有真正通知成功mq里面的消息才会被真正消息,如果这里抛异常,那么mq里面的消息相当于没有成功被消息,下次依然会进行入库,通知操作。
- http通知商户有问题,那么通知服务会每隔1,5,10,30分钟重复通知。如果达到最大通知次数依然没有通知成功,那么后续的数据还是保存在通知库里面,通过cmp进行管理,后续商户有通知需求的时候,通过人工的操作cmp,重新重置通知次数,这样消息又可以重新通知了,达到了最大努力通知的一个方案。
具体的方案协议细节如下图:
/**
* ————————如果觉得本博文还行,别忘了推荐一下哦,谢谢!
* 作者:写程序的奥特曼
* 欢迎转载,请保留此段声明。
* 出处:https://my.oschina.net/u/2286631/blog/1505151
*/