分布式事务方案 - 最终一致性

在分布式时代,分库分表是很常见的,微服务系统中,各个系统一般使用独立的数据库,因此,事务很难靠数据库自己保证,只能靠业务系统来解决。java

例如支付宝中的余额宝、花呗,具体不清楚,但猜想应该就是2个服务,不是同一个数据库,咱们还花呗的时候一般都是从余额宝中扣除的,这就是分布式事务,一个系统中扣减钱,一个系统中增长钱。数据库

下面咱们分析下最终一致性的实现方案,最终一致性一般都是使用消息中间件来实现的,系统结构以下:微信

在这里插入图片描述
用户向系统A发起转帐请求,A先在本身的数据库中扣钱,而后经过消息中间件告诉B应该加钱,B收到后在本身的数据库中加钱。网络

这里有个关键问题,A更新数据库和给消息中间件发消息是2个操做,以下两个场景怎么处理:分布式

先更新数据库,成功了,但发送消息失败了,重发屡次仍是失败微服务

先发消息,成功了,但数据库更新失败,消息撤不回来了性能

都是由于这2个操做不是原子的,发作谁都有问题。code

那看下这样作是否能够,就是把更新数据库和给消息中间件发消息放到一个事务中,这样不就原子了吗?中间件

有问题,例如:blog

若是消息发送失败,具体问题出在哪儿?是消息中间件根本就没收到消息,仍是收到消息后response时出错了?若是是根本没收到还好一点,若是是收到了但响应失败就麻烦了,致使A数据库回滚,没有扣钱,但B收到消息了,加钱了。

若是发消息时网络延迟很高怎么办,数据库事务一直被拖着,性能差,风险高。

因此,放入一个事务中这种方法是不可取的。

为了保证原子性,能够变通一下,添加一个消息表,A不直接往消息中间件中发消息,而是把消息写入消息表,而后经过一个后台程序不断的把消息写入消息中间件。

在这里插入图片描述

这个后台程序源源不断的把消息表中的消息发到消息中间件,若是失败就重试,能够保证:

消息不会丢失

顺序不乱

但会有消息重复的状况,由于消息发送失败多是写入失败,也多是写入成功但响应失败,因此消息可能会重复,这个问题须要系统B来处理。

系统B须要考虑2个问题:

消息丢失

B从消息中间件中拿到消息,还没处理完就宕机了,这条消息怎么办?

须要经过ACK机制处理,消费成功的发送ACK,对于没有ACK的消息,消息中间件会再次推送。

消息重复

ACK机制也存在消息重复的状况,好比B已经处理完一条消息,发ACK时失败了,那么这条消息就还会被推过来。

还有就是上面说的后台程序发消息时可能重复。

对于重复消息问题,能够加一个判重表,记录处理成功的消息,每次收到消息时,先经过判重表判断一下,若是重复了就不处理,实现幂等性。

这样,总体结构就变为:

在这里插入图片描述

以上就是经过最终一致性解决分布式事务问题的基本思路,A 保证消息不丢,B 保证消息不漏、幂等。

对分布式事务有兴趣、或有疑问的,能够加我微信itsoku交流

请关注公众号javacode2018,免费领取年薪40万的资料,更多好文及时推送给您

相关文章
相关标签/搜索