分布式事务的解决方案
分布式事务的解决方案
可随着业务量的不断增长,单体架构渐渐扛不住巨大的流量,此时就需要对数据库、表做 分库分表
处理,将应用 SOA
服务化拆分。也就产生了订单中心、用户中心、库存中心等,由此带来的问题就是业务间相互隔离,每个业务都维护着自己的数据库,数据的交换只能进行 RPC
调用。
当用户再次下单时,需同时对订单库 order
、库存库 storage
、用户库 account
进行操作,可此时我们只能保证自己本地的数据一致性,无法保证调用其他服务的操作是否成功,所以为了保证整个下单流程的数据一致性,就需要分布式事务介入。
Seata 优势
实现分布式事务的方案比较多,常见的比如基于 XA
协议的 2PC
、3PC
,基于业务层的 TCC
,还有应用消息队列 + 消息表实现的最终一致性方案,还有今天要说的 Seata
中间件,下边看看各个方案的优缺点。
2PC
基于 XA 协议实现的分布式事务,XA 协议中分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如 Oracle、MYSQL 这些数据库都实现了 XA 接口,而事务管理器则作为一个全局的调度者。
两阶段提交(2PC
),对业务侵⼊很小,它最⼤的优势就是对使⽤⽅透明,用户可以像使⽤本地事务⼀样使⽤基于 XA 协议的分布式事务,能够严格保障事务 ACID 特性。
可 2PC
的缺点也是显而易见,它是一个强一致性的同步阻塞协议,事务执⾏过程中需要将所需资源全部锁定,也就是俗称的 刚性事务
。所以它比较适⽤于执⾏时间确定的短事务,整体性能比较差。
一旦事务协调者宕机或者发生网络抖动,会让参与者一直处于锁定资源的状态或者只有一部分参与者提交成功,导致数据的不一致。因此,在⾼并发性能⾄上的场景中,基于 XA 协议的分布式事务并不是最佳选择。
3PC
三段提交(3PC
)是二阶段提交(2PC
)的一种改进版本 ,为解决两阶段提交协议的阻塞问题,上边提到两段提交,当协调者崩溃时,参与者不能做出最后的选择,就会一直保持阻塞锁定资源。
2PC
中只有协调者有超时机制,3PC
在协调者和参与者中都引入了超时机制,协调者出现故障后,参与者就不会一直阻塞。而且在第一阶段和第二阶段中又插入了一个准备阶段(如下图,看着有点啰嗦),保证了在最后提交阶段之前各参与节点的状态是一致的。
虽然 3PC
用超时机制,解决了协调者故障后参与者的阻塞问题,但与此同时却多了一次网络通信,性能上反而变得更差,也不太推荐。
TCC
所谓的 TCC
编程模式,也是两阶段提交的一个变种,不同的是 TCC
为在业务层编写代码实现的两阶段提交。TCC
分别指 Try
、Confirm
、Cancel
,一个业务操作要对应的写这三个方法。
以下单扣库存为例,Try
阶段去占库存,Confirm
阶段则实际扣库存,如果库存扣减失败 Cancel
阶段进行回滚,释放库存。
TCC 不存在资源阻塞的问题,因为每个方法都直接进行事务的提交,一旦出现异常通过则 Cancel
来进行回滚补偿,这也就是常说的补偿性事务。
原本一个方法,现在却需要三个方法来支持,可以看到 TCC 对业务的侵入性很强,而且这种模式并不能很好地被复用,会导致开发量激增。还要考虑到网络波动等原因,为保证请求一定送达都会有重试机制,所以考虑到接口的幂等性。