什么是事务
概念
事务是指一系列操作组成的一个程序执行工作单元,通俗的来讲就好比一个大的活动,它是通过多个小活动所组成的。这些活动要么全部成功,要么全部失败,不存在部分成功或者部分失败的情况。
特性
在事务中有四大特性(ACID),分别是原子性(Atomicty)、一致性(Consistency)、隔离性(Isolation)与持久性(Durability)。
- 原子性(A): 事务中的各项操作要么全部执行成功,要么全部不执行,任何一项操作失败,都将导致整个事务失败。同时之前已经执行过的操作都需要被撤销和回滚。只有所有的操作全部执行成功,整个事务才算成功。
- 一致性(C): 事务的执行不能破坏数据库数据的完整性和一致性,在事务执行前以及执行后,数据库都必须处于一致性状态。
- 隔离性(I): 通常是指在并发环境中,并发执行的两个事务互不干扰。即不同的事务在操作同一块数据时,每个事务都有独立且完整的数据空间。
- 持久性(D): 事务一旦提交,那么表明该事务已经结束。该事务对数据库进行的操作都应该被永久保存下来,即便是发生宕机或者其它故障,只要数据库能重启成功,就应该要回到事务成功结束时的状态。
本地事务 or 分布式事务
简单而言,在项目系统初期体量并不大,使用单体架构能够满足业务需要。所有的业务共用一个数据库,一套业务流程下执行只需要通过本地事务操作数据库即可。
随着业务量的增长,单体架构再也抗不住大流量,需要进行业务服务拆分,数据库方面根据业务需要进行分库分表。业务之间相互隔离,每个业务维护自己的数据库,数据交换通过RPC远程调用。当我们再去执行业务流程操作时,只能保证当前服务的本地事务的数据一致性,其它服务的操作是否成功无法保证。那么根据这种情况,为了保证数据的一致性,就需要引入分布式事务。
分布式事务的理论依据
两大理论依据:
- CAP定理
- BASE理论
CAP定理
分布式系统下的三个指标:
- 一致性(C): 强一致性,即用户访问分布式系统中的任意节点,得到的数据必须一致。
- 可用性(A):用户访问集群中的任意健康节点,必须能够得到响应,不能超时或者拒绝。
- 分区容错性(P):分布式系统遇到某节点或者网络分区故障时,仍然能够对外提供满足一致性或者可用性的服务。
在分布式系统中,P是必然存在的,没有P就不算是分布式系统,那么只能在C和A之间做取舍。
- CP:在一定时间内,等待集群节点进行数据同步后,再对外提供服务。
- AP:在任何时间内,都能够对外提供服务,但是不保证每次得到的数据都是一致的。
BASE理论
对CAP的一种补充,舍弃强一致性,追求最终一直性。
- 基本可用: 分布式系统出现故障时,允许损失部分可用性(非核心服务),保证核心服务可用。
- 软状态:在一定时间内,允许出现中间状态,例如临时的不一致。
- 最终一致性:虽然无法保证强一致性,但是当软状态结束后,最终达到数据一致即可。
Seata解决分布式事务
Seata简介
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,为用户提供了 AT、TCC、SAGA 和 XA 事务模式。
Seata中的主要角色
- TC(Transaction Coordinator): 事务协调者。管理全局的分支事务状态,用于全局性事务的提交和回滚。
- TM(Transaction Manager):事务管理者。用于开启、提交或回滚事务。
- RM(Resource Manager):资源管理器。用于分支事务上的资源管理,向TC注册分支事务,上报分支事务的状态,接收TC的命令来提交或者回滚分支事务。
四种事务模式
- AT:最终一致分阶段事务模式,无业务代码侵入(默认事务模式)
- XA:强一致性分阶段事务模式,无业务代码侵入,牺牲了一定的可用性
- TCC:最终一致的分阶段事务模式,每个服务都有Try阶段、Confirm阶段、Cancel阶段,有业务侵入
- Saga: 长事务模式,有业务代码侵入
Seata - AT模式
先讲一讲AT模式(默认的事务模式) ,两阶段提交(2PC)的演变:
一阶段(执行阶段): 每个微服务请求完成后,基于本地数据库的事务,保证业务数据和回滚日志在同一个本地事务里提交,快速释放连接和对资源的锁定;
二阶段(完成阶段):全局提交时分支事务已经完成提交,清理回滚日志快速结束流程。全局事务回滚基于XID和BranchID查询回滚日志,完成数据回滚。
工作原理:
Seata - XA模式
然后再来看一下XA模式,利用数据库、消息服务等资源对XA协议的支持,以XA协议机制来管理分支事务。
XA协议规范是什么?
XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准。
XA 规范 描述了全局的事务管理器与局部的资源管理器之间的接口。XA规范 的目的是允许的多个资源(如数据库,应用服务器,消息队列等)在同一事务中访问,这样可以使 ACID 属性跨越应用程序而保持有效。
XA 规范 使用两阶段提交(2PC,Two-Phase Commit)来保证所有资源同时提交或回滚任何特定的事务。
DTP定义了如下几个角色:
AP: 应用程序,使用DTP分布式事务的应用程序。
RM: 资源管理器,事务的参与者。
TM: 事务管理器,负责管理整个事务的生命周期并且协调各个RM(资源管理器)。
XA协议问题在于,如果一个参与全局事务的资源长时间收不到分支事务的命令,这会导致数据锁一直无法被释放,甚至发生死锁问题。那么当Seata在引入XA模式时,该问题需要被解决。
Seata XA模式同样也是两阶段提交的演变:
- 一阶段(执行阶段): 业务操作放在XA分支中进行,XA分支的事务执行完成后,执行XA Prepare,通过数据库等资源对XA协议的支持保证可回滚与持久化。
- 二阶段(完成阶段): TM(事务管理者)根据执行阶段的执行结果形成决议,应用通过TM(事务管理者)发起全局提交或者回滚请求给到TC(事务协调者),然后TC(事务协调者)命令RM(资源管理器)驱动分支事务进行提交或者回滚。
工作原理:
在增加XA模式之前,已经支持AT、TCC、Saga三种事务模式,属于补偿型事务模式。此类事务模式机制建立在事务资源之上,事务资源本身对分布式事务是无感知的,由此衍生出一个根本性问题就是无法做到真正的全局一致性(存在中间状态)。XA协议要求事务资源本身提供对规范和协议的支持,从根本上满足全局数据一致性,事务资源感知并参与分布式事务的处理过程。
除此之外,XA模式还有如下优点:
- 业务无侵入:业务无侵入,没有额外的开发负担。
- 数据库支持:主流关系型数据库均支持。
- 多语言支持:不涉及SQL解析,对Seata RM要求较少。
- 平滑迁移:传统基于XA协议的应用迁移到Seata平台,无需过多变动。
Seata - TCC模式
TCC(Try-Confirm-Cancel),将数据库的两阶段提交协议提升到应用层面,属于柔性事务方案。
核心思想: 针对业务流程的每个操作,都要注册一个与其对应的确认和补偿操作。
主要分为两个阶段:
- 一阶段: Try尝试,对业务系统做资源预留以及检测(锁资源)
- 二阶段: 根据一阶段的结果,最终决定是操作确认还是取消补偿
操作确认(Confirm): 执行实际的业务操作,提交commit
取消补偿(Cancel): 取消预留资源 如果要使用TCC,那么所有参与同一个分布式事务的服务都需要准备上面的三个接口,对业务系统有很强的侵入性。优点也很明显,不需要依赖数据库,能够实现跨数据库、跨应用的资源管理。通过自定义的分支事务,将其纳入到全局事务管理。
特点:
1、不保证强一致性,保证最终一致性。核心链路出现数据异常情况,通过调度任务或者消息MQ实现兜底补偿,同时做好消息记录,方便后续人工干预;
2、代码侵入性强,每个参与事务的分支都需要实现try、confirm和cancel操作,并且confirm和cancel操作都需要保证幂等性。
TCC空回滚与业务悬挂问题
- 空回滚:
在一个分布式事务中,在没有调用参与者Try方法的情况下,TM(事务管理器)调用了参与方的Cancel方法。
解决方案: 要想防止空回滚,就必须在Cancel方法中识别这是一个空回滚,在二阶段执行回滚rollback的时候,先检查一阶段有没有执行过Try方法,执行过才能执行rollback方法,如果没有执行就不做任何操作。Seata的做法是增加一个事务控制表tcc_fence_log,当Try方法执行成功后就在tcc_fence_log表中新增一条记录。需要进行回滚时,先去查询tcc_fence_log表中是否存在Try阶段执行成功的记录,存在就执行rollback,不存在表明Try方法没有执行,就不做其它操作。 - 业务悬挂:
简单理解就是Cancel方法比Try方法先执行,以至于Try阶段预留的资源无法回滚。 Try阶段执行时间长超时,TC会认为现有服务异常,需要回滚补偿执行Cancel方法,在调用完Cancel之后Try方法也执行成功了,就导致了Try预留的资源没办法回滚。
解决方案:TCC事务控制表记录状态的字段增加一个状态类型(suspended),当执行Cancel方法时,如果发现事务控制表中存在相关记录,说明Cancel方法优先Try方法执行,插入一条状态(status为suspended)的记录。Try方法再执行时,判断status是否为suspended,如果存在说明Cancel方法已经执行,则阻止Try方法执行成功。
Seata - Saga模式
Saga模式是Seata提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
适用场景:
1、业务流程长、业务流程多
2、参与者包含其它公司(外部三方系统)或者遗留系统服务,无法提供TCC模式必须的三个接口
优点:
1、一阶段提交本地事务,无锁,高性能
2、事件驱动架构,参与者可以异步执行,高吞吐
3、补偿服务易于实现
缺点:
- 不保证隔离性: 一阶段和二阶段既没有全局锁,也没有预留资源,事务与事务之间存在脏写的可能
- 软状态的持续时间不确定: 原则上是按顺序执行每一个事务,如果有任何一个事务出现问题,就会立即反向补偿,不一致的时间不确定。
缺乏隔离性的应对
- 由于 Saga 事务不保证隔离性, 在极端情况下可能由于脏写无法完成回滚操作, 比如举一个极端的例子, 分布式事务内先给用户A充值, 然后给用户B扣减余额, 如果在给A用户充值成功, 在事务提交以前, A用户把余额消费掉了, 如果事务发生回滚, 这时则没有办法进行补偿了。这就是缺乏隔离性造成的典型的问题, 实践中一般的应对方法是:
-- 业务流程设计时遵循"宁可长款, 不可短款"的原则, 长款意思是客户少了钱机构多了钱, 以机构信誉可以给客户退款, 反之则是短款, 少的钱可能追不回来了。所以在业务流程设计上一定是先扣款。
-- 有些业务场景可以允许让业务最终成功, 在回滚不了的情况下可以继续重试完成后面的流程, 所以状态机引擎除了提供"回滚"能力还需要提供"向前"恢复上下文继续执行的能力, 让业务最终执行成功, 达到最终一致性的目的。
Saga状态机
目前Seata提供的Saga模式是基于状态机引擎来实现的,实现机制:
1、通过状态图来定义服务调用的流程并生成 json 状态语言定义文件
2、状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点
3、状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚(注: 异常发生时是否进行补偿也可由用户自定义决定)
4、可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能
示例状态图如下:
四种事务模式对比:
总结
以上就是关于事务原理以及分布式事务中间件Seata相关介绍,技术领域没有哪一项是最优解,而是需要根据实际业务情况,采取适合自身业务的方案才是最重要的。之后会分享分布式事务的另外几种解决方案,感兴趣的朋友可以点点关注、点点赞,非常感谢! 再会~~