本地事务
事务Transaction由一组SQL组成,具有四个ACID特性
ACID
Atomicity 原子性
Consistency 一致性
isolation 隔离性
durability 持久性
事务实现
对于MySQL数据库(InnoDB存储引擎)而言,隔离性是通过不同粒度的锁机制来实现事务间的隔离;原子性、一致性和持久性通过redo log 重做日志和undo log回滚日志来保证的。
redo log
undo log
问题引入
CAP理论
CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。但由于在分布式系统中,分区容错性必然存在,所以只能在一致性和可用性妥协。
传统的DBMS,如MySQL其实CA组合,在主从架构下,读写分离的情况下,是牺牲一定的一致性的(主从延迟)。
Base理论
base available 基本可用
soft state 软状态
eventually consistent 最终一致性
如何解决
场景举例
考虑这样一种业务场景,系统A调用系统B的退款服务进行退款,系统A更改内部退款状态,接着调用系统C的短信服务通知用户。
在这样的一个场景下,由于网络不可靠的必然存在,存在A、B、C三个系统之间一致性的问题。
本地表
针对上述场景,设计两张表 退款记录表 和 短信发送记录表 以及 相应的补偿Job
具体实现过程:
- 新增退款记录表,状态为处理中
- 调用系统B的退款服务进行退款
- 更新退款记录状态为对应的状态(成功/失败)
- 如果退款成功,则新增短信发送记录,记录状态为待发送
- 调用系统C的短信服务,发送短信
- 更新短信发送记录为已发送
退款补偿Job
- 新增短信发送记录,记录状态为待发送
- 调用系统C的短信服务,发送短信
- 更新短信发送记录为已发送
短信通知补偿Job
- 调用系统C的短信服务,发送短信
- 更新短信发送记录为已发送
注意:
- 系统B和系统C需要根据调用方传的uuid支持幂等
- 系统A、B、C会出现短暂的不一致,但最终一致
事务消息
可以将其视为两阶段提交消息实现,以确保分布式系统中的最终一致性。事务性消息可确保本地事务的执行和消息的发送可以原子方式执行。
但是由于事务消息异步的特性,调用方拿不到消费方的处理结果,适用于不关心对方的返回结果/对方负责保证处理成功
针对上述场景,增加两个事务消息的方式解决一致性问题,系统A通过发送事务消息的方式与系统B和系统C进行交互
具体实现过程:
- 发送退款的事务消息
- 新增退款记录,状态为:处理中
- Commit退款事务消息
提供MQ事务callback
退款callback查询
- 有退款记录且为处理中则Commit
- 其他则Rollback
发送短信callback查询
- 有退款记录且成功则Commit
- 其他则Rollback
退款同步Job
查询退款记录表中处理中的记录,调用系统B的退款查询接口 同步状态 其中退款成功处理:
- 发送短信的事务消息
- 更新退款记录为成功
- Commit短信事务消息
相关理论
二阶段提交
二阶段提交是解决分布式事务问题的重要理论基础,但也存在着明显的问题:
- 阻塞问题,参与者将协议消息发送给协调器后,它将阻塞直到收到提交或回滚,只能依赖协调者的超时机制
- 协调者单点问题,如果协调者出现故障,则某些参与者将一直无法收到提交或回滚的消息。
为了解决二阶段提交出现的问题,又有了三阶段提交(Three-phase commit):
- 解决阻塞问题:将2PC中的第一阶段一分为二,提供了一个CanCommit阶段,此阶段并不锁定资源,这样可以大幅降低了阻塞概率
- 解决单点问题:在参与者这边也引入了超时机制
DTP Model
X / Open分布式事务处理DTP(Distributed Transaction Processing)模型是一种软件体系架构,已经成为事实上的事务模型组件的行为标准。它允许多个应用程序共享由多个资源管理器提供的资源,并允许其工作被协调为全局事务。
ApplicationProgram(AP)
ResourceManager(RM)
TransactionManagger(TM)
CommunicationResourceManager(CRM)
XA Specification
XA规范是X/Open关于分布式事务处理 (DTP)的规范。规范描述了全局的事务管理器与局部的资源管理器之间的接口。XA规范的目的是允许多个资源(如数据库,应用服务器,消息队列,等等)在同一事务中访问,这样可以使ACID属性跨越应用程序而保持有效。XA使用两阶段提交来保证所有资源同时提交或回滚任何特定的事务。
XA规范描述了资源管理器要支持事务性访问所必需做的事情。
TCC
saga
在 Saga 模式下,分布式事务内有多个参与者,每一个参与者都是一个冲正补偿服务,需要用户根据业务场景实现其正向操作和逆向回滚操作。
分布式事务执行过程中,依次执行各参与者的正向操作,如果所有正向操作均执行成功,那么分布式事务提交。如果任何一个正向操作执行失败,那么分布式事务会去退回去执行前面各参与者的逆向回滚操作,回滚已提交的参与者,使分布式事务回到初始状态。
Saga 模式下分布式事务通常是由事件驱动的,各个参与者之间是异步执行的,Saga 模式是一种长事务解决方案。
Saga模式的优势是:
- 一阶段提交本地数据库事务,无锁,高性能;
- 参与者可以采用事务驱动异步执行,高吞吐;
- 补偿服务即正向服务的“反向”,易于理解,易于实现;
缺点:
- Saga 模式由于一阶段已经提交本地数据库事务,且没有进行“预留”动作,所以不能保证隔离性。
开源项目
seata
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。支持AT、TCC、SAGA、XA四种模式,对微服务框架支持友好。
如下图所示,Seata 中有三大模块,分别是 TM、RM 和 TC。其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。
TC - 事务协调者
TM - 事务管理器
RM - 资源管理器
在 Seata 中,分布式事务的执行流程:
- TM 开启分布式事务(TM 向 TC 注册全局事务记录);
- 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 );
- TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务);
- TC 汇总事务信息,决定分布式事务是提交还是回滚;
- TC 通知所有 RM 提交/回滚 资源,事务二阶段结束;
AT模式
AT 模式是一种无侵入的分布式事务解决方案。在 AT 模式下,用户只需关注自己的“业务 SQL”,用户的 “业务 SQL” 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。
在一阶段,Seata 会拦截“业务 SQL”,首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
TCC模式
一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
一阶段 prepare 行为 二阶段 commit 或 rollback 行为
TCC 模式,不依赖于底层数据资源的事务支持:
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。
Saga模式
目前SEATA提供的Saga模式是基于状态机引擎来实现的,机制是:
- 通过状态图来定义服务调用的流程并生成 json 状态语言定义文件
- 状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点
- 状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚 (异常发生时是否进行补偿也可由用户自定义决定)
- 可以实现服务编排需求,支持单项选择、并发、子流程、参数转换、参数映射、服务执行状态判断、异常捕获等功能
状态机引擎原理
- 图中的状态图是先执行stateA, 再执行stateB,然后执行stateC
- "状态"的执行是基于事件驱动的模型,stateA执行完成后,会产生路由消息放入EventQueue,事件消费端从EventQueue取出消息,执行stateB
- 在整个状态机启动时会调用Seata Server开启分布式事务,并生产xid, 然后记录"状态机实例"启动事件到本地数据库
- 当执行到一个"状态"时会调用Seata Server注册分支事务,并生产branchId, 然后记录"状态实例"开始执行事件到本地数据库
- 当一个"状态"执行完成后会记录"状态实例"执行结束事件到本地数据库, 然后调用Seata Server上报分支事务的状态
- 当整个状态机执行完成, 会记录"状态机实例"执行完成事件到本地数据库, 然后调用Seata Server提交或回滚分布式事务
原作者:VectorJinlv