Fork me on GitHub

使用MQ来保证分布式事务的最终一致性

前言

之前我们讨论了如何拆分一个订单下单的一个服务(https://www.cnblogs.com/linkstar/p/9610268.html)
从单体到微服务的拆分,当时我们只是对原来的整个服务做了一个简单的拆分,但是在实际中肯定会遇到很多问题,所以我们这里解决一个最容易也是最有可能在实际中遇到的问题,事务。

在单体架构中,我们很容易去维护一个事务,我们想要对一个事务操作回滚也很容易,而在分离成微服务之后,我们想要在多个服务上去维护一个事务就比较困难了。这里我们不再讨论分步事务的实现,转而讨论一个我们常常听到的,最终一致性。

简单的说,很多在实际中的应用多数情况下,想要保证的是只要最后的最结果是对的,中间的过程可能几经周折都没有关系。

我们继续拿下单这个例子,想要保证的是,只要最后钱扣了,订单生产了,就对了。假设其中的一个服务挂了,可能经过不断的重试,最终等服务正常之后,结果还是对了,也就满意。针对这样的情况,我们称为“最终一致性”。(这里对于它不再过多解释)

使用MQ的原因

那么针对最终一致性为什么要使用mq呢?我想很多人也知道网上很多人在说mq实现最终一致性,但是从来没有仔细想想为什么要用mq。我列出这几个原因来供你参考:
1、mq可以解决http请求出现异常的时候带来的一系列问题
2、mq可以有多个消费者,完全契合微服务
3、mq本质是队列,在高并发下,可以保证你的数据正常
...

逻辑流程图

生产者的逻辑
1、订单入库
2、消息记录入库
3、发送消息(采用确认模式)
4、mq收到消息之后给生产端一个确认消息
5、生产端监听这个确认消息
6、根据监听结果操作消息表的状态
7、定时任务定时去操作消息状态为1未发送的记录,就是那些没有监听到结果的记录进行重新发送

消费者的逻辑
1、将收到消息的消息入库
2、处理消息失败消息记录的状态就为未处理
3、处理消息成功修改消息记录的状态为处理成功
4、收到相同的消息id的消息直接丢弃
5、定时任务去操作那些未处理,并且已经经过一段时间的消息
6、针对那些一直处理失败的,且很长一段时间都没办法处理成功的消息交由人工或者其他途径处理

需要注意的问题

1、消息的100%投递
首先我们需要保证的就是消息一定要投递出去,要是我们消息都不能保证投递成功,那么后面的逻辑就走不下去了。

2、我们需要保证幂等性(无论多少次操作,最后造成的结果和只执行一次造成的结果是一样的。)
消息肯定会出现重复投递的问题,这里应该由消费端去保证,重复的消息不能进行消费

而保证这两个问题的方式就藏在上面的逻辑流程图中,请仔细揣摩其中的用意。

代码实现

https://github.com/LinkinStars/MicroServiceExample/tree/distributed-transaction

参考博客

https://segmentfault.com/a/1190000012762869

具体其他细节这里讲的很清楚,这里不再赘述,针对分布式事务,一直都是一个难题,当前的解决方案有很多,适应不同的应用场景,所以需要根据实际项目使用场景来选取。

 

posted @ 2018-10-13 21:24  LinkinStar  阅读(4804)  评论(2编辑  收藏  举报