✅常见的分布式事务有哪些?
典型回答
分布式事务的目的是保证分布式系统中的多个参与方的数据能够保证一致性。即所有参与者,在一次写操作过程中要么都成功,要么都失败。
至于这个一致性到底是怎样的一致性,是强一致性、还是最终一致性,不同的分布式事务方案其实达到的效果并不相同。
以下是常见的一些方案和相关介绍。
| 方案 | 一致性 | 介绍 | 特点 | 常见中间件 |
|---|---|---|---|---|
| XA(2PC/3PC) | 强一致性 | https://www.yuque.com/hollis666/sza8tg/du7xnm https://www.yuque.com/hollis666/sza8tg/zt707p4ypq68grpf |
严格一致,但性能差,容易阻塞资源 | Atomikos、Narayana、MySQL XA |
| TCC | 最终一致性 | https://www.yuque.com/hollis666/sza8tg/xhvbak3ouy6xqiml | 业务侵入大、灵活性高、适合高价值场景 | Seata TCC、Hmily TCC |
| Saga | 最终一致性 | 异步、非阻塞,适合长事务 | Seata Saga、Apache ServiceComb Saga | |
| Seata AT | 最终一致性 | https://www.yuque.com/hollis666/sza8tg/me3ge4vavi0fokgq | 自动化高、侵入小,仅支持关系型数据库 | Seata AT |
| 本地消息表 | 最终一致性 | https://www.yuque.com/hollis666/sza8tg/xm675quxo1bc5qm8 | 架构灵活、复杂度中等 | RocketMQ、Kafka + 自研方案 |
| 事务消息 | 最终一致性 | https://www.yuque.com/hollis666/sza8tg/awrtlggd35yanugp | 不阻塞、适合异步场景 | RocketMQ 事务消息 |
| 最大努力通知 | 弱一致性 | https://www.yuque.com/hollis666/sza8tg/akhq6shbaqc61s5n | 简单、高性能、不适合核心业务 | RocketMQ普通消息 |
强一致性方案
如果想要实现强一致性,那么就一定要引入一个协调者,通过协调者来协调所有参与者来进行提交或者回滚。所以,这类方案包含基于XA规范的二阶段及三阶段提交、以及支持2阶段提交。
最终一致性方案
如果想要实现最终一致性,那么方案上就比较简单,常见的基于可靠消息的最终一致性(本地消息表、事务消息)。
可靠消息最终一致性,顾名思义就是依赖可靠的消息,来实现一种最终一致性的模型。
他的大致流程就是:
1、事务的发起方执行本地事务
2、事务的发起方向事务的参与方发送MQ消息
3、事务的参与方接收到MQ消息后执行自己的本地事务
这里面事务的发起方和参与方都需要各自执行本地事务,他们之间,通过可靠消息来保障最终一致。
那么,怎么样的消息算可靠呢,直接依赖kafka、rocketMQ发送一个消息就可靠了么?显然是不行的,因为我们知道,在出现网络分区、网络延迟等情况时,是没办法保证消息一定可以发出去的,也没办法保证消息发出去就一定能被成功消费。
那么想要做到让这个消息可靠,一般由两种做法,一个是事务消息、一个是本地消息表。
通过这两种方案,都可以保证事务的发起方在执行完本地事务之后,消息一定可以发出去,并且一定能被消费成功。
本地消息表的方案是基于本地事务+重试,来保证MQ消息一定可以发出去。
事务消息的方案是基于MQ的事务消息机制,把一条消息拆成两个half消息,通过2阶段的方式+回调反查来保证消息一定能发出去。
2者都是依赖MQ自身的重试机制+事务参与者反查+对账来保证消息一定可以消费。
另外,还有我们比较熟知的TCC,TCC也是一种最终一致性的方案,他通过把一个事务操作拆分成Try,Confirm,Cancel三个步骤,引入了中间状态,而这种"中间状态",就意味着他已经不是强一致性了。
弱一致性方案
所谓弱一致性,其实就是不保证最终一致状态,也不保证读取的时效性,只保证“尽力而为”,那么,我们常用的弱一致性方案就是 最大努力通知了,他是典型的弱一致性方案。
Seata
另外,还有一些分布式事务的组件,如阿里的Seata,他其实是一个开源的分布式事务解决方案,旨在为微服务架构提供高效且透明的事务管理。在讨论 Seata 的一致性特性时,需要明确其支持的不同事务模式,因为每种模式对一致性的保证不同。
Seata提供了很多种事务方式,包括XA、TCC等等,也有他自己独特的AT、Saga等模式。这两种都是最终一致性。
| 对比项 | XA | AT | TCC | Saga |
|---|---|---|---|---|
| 一致性 | 强一致 | 最终一致 | 最终一致性 | 最终一致 |
| 隔离性 | 完全隔离 | 基于全局锁隔离 | 基于资源预留隔离 | 无隔离 |
| 代码侵入性 | 无 | 无 | 有,要编写TCC三个接口 | 有,要编写状态机及补偿代码 |
| 性能 | 差 | 高 | 非常高 | 非常高 |
| 适用场景 | 对一致性、隔离性要求较高的场景 | 基于关系型数据库的大多数分布式事务场景 | 对性能要求高的场景,有非关系型数据库要参与的事务 | 业务流程长且多。参与者包含外部接口或者遗留接口,无法做TCC模式的 |
扩展知识
如何选择
在选择一个分布式事务方案的时候,需要考虑很多因素,结合自己的业务来做考量选择。一般来说可以有以下几种选择方式:
1、实现成本:根据项目开发和维护的难度、成本等方面来选择合适的分布式事务方案。这几种方案中,TCC和2PC的实现成本最高,业务侵入性也比较大。
另外,事务消息、本地消息表和最大努力通知都依赖消息中间件,所以如果已有业务已经接入了消息中间件的话,那么使用成本还算可控,否则就需要考虑消息中间件部署、维护和接入成本。而且同样是消息中间件,也不是所有的都支持事务消息,这个也是需要考量的一个重要因素。
**2、一致性要求:**在一致性方面,2PC、3PC、XA 等等都属于是可以保证强一致性的,而其他的几种方案是最终一致性的方案。
根据业务情况,比如下单环节中,库存扣减和订单创建可以用强一致性来保证。而订单创建和积分扣减就可以用最终一致性即可。而对于一些非核心链路的操作,如核对等,可以用最大努力通知即可。
**3、可用性要求:**根据CAP理论,可用性和一致性是没办法同时保证的,所以对于需要保证高可用的业务,建议使用最大努力通知等最终一致性方案;对于可用性要求不高,但是需要保证高一致性的业务,可使用2PC等方案。
**4、数据规模:**对于利用消息中间件的这种方案,其实不是特别适合业务量特别大的场景,有可能出现消息堆积导致一致性保障不及时。对于数据量大的场景,可以考虑Seata方案。