文章内容输出来源:拉勾教育Java高薪训练营
1.介绍
分布式事务是指单个事件导致两个或多个不能以原子方式提交的单独数据源的突变的任何情况。在微服务中,它变得更加复杂,因为每个服务都是一个工作单元,并且大多数时候多个服务必须协同工作才能使业务成功。
数据库事务特性: ACID
原⼦性(Atomicity): 原⼦性是指事务是⼀个不可分割的⼯作单位,事务中的操作要么都发⽣,要么都
不发⽣。从操作的⻆度来描述,事务中的各个操作要么都成功要么都失败。
⼀致性(Consistency): 事务必须使数据库从⼀个⼀致性状态变换到另外⼀个⼀致性状态。
例如转账前 A 有 1000, B 有 1000。转账后 A+B 也得是 2000。
⼀致性是从数据的⻆度来说的,(1000, 1000) (900, 1100),不应该出现(900,1000)
隔离性(Isolation): 事务的隔离性是多个⽤户并发访问数据库时,数据库为每⼀个⽤户开启的事务,每个事务不能被其他事务的操作数据所⼲扰,多个并发事务之间要相互隔离。
⽐如:事务1给员⼯涨⼯资2000,但是事务1尚未被提交,员⼯发起事务2 查询⼯资,发现⼯资涨了2000块钱,读到了事务1尚未提交的数据(脏读)。
持久性(Durability): 持久性是指⼀个事务⼀旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发⽣故障也不应该对其有任何影响。
分布式理论: CAP定理和BASE理论
当单个数据库性能产生瓶颈的时候,可能会对数据库进行分区(物理分区),分区之后不同的数据库不同的服务器
上,此时单个数据库的ACID就不适应了,在此集群环境下很难达到集群的ACID,甚至效率性能大幅度下降,重要的是再很难扩展新的分区了。此时就需要引用一个新的理论来使用这种集群情况:CAP 定理
CAP 定理: 该定理指出WEB服务无法同时满足3 个属性:
一致性: 客户端知道一系列的操作都会同时发生(生效)
可用性: 每个操作都必须以可预期的响应结束
分区容错性: 即使出现单组件无法可用,操作依然可以完成。
具体的将在分布式系统中,在任何数据库设计中,一个WEB 应用至多只能同时支持上面两个属性。设计人员必须在一致性和可用性之间做出选择。
BASE 理论: 分布式系统中追求的是可用性,比一致性更加重要,BASE 理论来实现高可用性。核心思想是:我们无法做到全一致,但是每个应用都可以根据自身的业务特点,采用适当的方式使系统达到最终一致性。
2.分布式事务解决方案
分布式事务的解决方案主要有以下 5 种:
(1)XA方案(两阶段提交方案)
(2)TCC方案
(3)Saga方案(事务补偿方案)
(4)基于消息队列方案(可靠消息最终一致性方案)
(5)Seata框架方案
(1)XA方案(两阶段提交方案)
XA 方案,即两阶段提交方案,有一个事务管理器的概念,负责协调多个数据库(资源管理器)的事务,事务管理器先问问各个数据库你准备好了吗?如果每个数据库都回复 ok,那么就正式提交事务,在各个数据库上执行操作;如果任何其中一个数据库回答不ok,那么就回滚事务。
这种方案适合单系统应用里,跨多个数据库的分布式事务,其基于Spring + JTA实现。
(2)TCC方案
TCC方案即采用Try-Confirm-Cancel模型。
- Try阶段,负责资源的检查和预留;
- Confirm阶段,提交操作,执行真正的业务;
- Cancel阶段,预留资源的取消;
TCC方案适合金融方面的业务,这种事务回滚实际上是严重依赖于你自己写代码来回滚和补偿了,会造成补偿代码巨大。实际使用是基于自己手写回滚逻辑,或者是补偿逻辑。
(3)Saga方案
Saga方案即在分布式事务场景下,我们把一个Saga分布式事务看做是一个由多个本地事务组成的事务,每个本地事务都有一个与之对应的补偿事务。在Saga事务的执行过程中,如果某一步执行出现异常,Saga事务会被终止,同时会调用对应的补偿事务完成相关的恢复操作,这样保证Saga相关的本地事务要么都是执行成功,要么通过补偿恢复成为事务执行之前的状态(自动反向补偿机制)。
Saga方案适合业务流程长、业务流程多的场景;比如参与者包含其它公司或遗留系统服务或第三方的系统接口或无法提供TCC模式要求的三个接口。
实际使用可以整合sharding-jdbc来使用:
//Saga模式
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-transaction-base-saga</artifactId>
<version>${shardingsphere-spi-impl.version}</version>
</dependency>
(4)基于消息队列,可靠消息最终一致性方案
基于消息队列本质是基于TCC模式,只是中间加入了MQ,消息中间件可以基于 Kafka、RocketMQ 等消息队列。此方案的核心是将分布式事务拆分成本地事务进行处理,将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或MQ中间件,再通过业务规则人工发起重试。
其过程为先是预提交阶段,执行A事务并发起确认阶段去执行B事务;若失败,MQ会调用A事务确认是再次发起确认请求还是回滚事务。此方案适合大部分普通事务场景;使用规则为引入消息中间件进行控制。
(5)Seata框架方案
Seata(Simple Extensible Autonomous Transaction Architecture)是一套一站式分布式事务解决方案,是阿里集团和蚂蚁金服联合打造的分布式事务框架。Seata目前的事务模式有AT、TCC、Saga和XA,默认是AT模式,AT本质上是2PC协议的一种实现。
在 Seata 中,AT时分为两个阶段的,第一阶段,就是各个阶段本地提交操作;第二阶段会根据第一阶段的情况决定是进行全局提交还是全局回滚操作。
Seata广泛应用在微服务架构中,使用时可以单独部署seata服务,然后进行分布式事务控制,也可以通过Sharding-JDBC整合Seata,然后在代码中设置相应的事务模式即可。
//Seata模式
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
3.分布式事务方案选择
如何选用分布式事务方案:
(1)对于资金问题的事务或要严格保证数据的一致性的事务可以采用TCC方案;
(2)对于业务流程长,模块多的事务控制可以采用saga方案;
(3)对于绝大多数的普通事务,可以采用消息队列补偿事务方案;
(4)对于微服务架构项目,可以采用seata框架方案。
实际项目的应用情况:
注意对于多个项目,不建议采用分布式事务控制,当多个服务每个服务都引入分布式事务控制,这样会提高代码复杂度,大大降低系统的性能,同时增加了维护成本;
注意对于99%的分布式接口调用,都不需要做分布式事务控制,而直接采用书写代码控制逻辑,比如直接监控(发邮件、发短信)、记录日志(错误日志,完整日志)、事后快速定位问题、排查和解决问题的方案、修复清洗数据等。
文章内容输出来源:拉勾教育Java高薪训练营
若有错误之处,欢迎留言指正~~~