一、分 布 式 服 务 购 物 逻 辑 伪 代 码 实 现
我们以快捷支付的方式在商城购买商品为例(即:下完订单自动支付),看一下分布式
事务在实现上与非分布式的区别。前提是我们针对
订单服务
、
库存服务
和
支付服务
这3个
服务都有对应的3个数据库,分别是
订单库
、
库存库
和
支付库
。伪代码如下所示:
二、分 布 式 事 务 解 决 方 案 概 述
2.1 刚性事务(强一致性事务)
XA
2PC
3PC
2.2 柔性事务(最终一致性事务)
可靠事件队列
TCC
SAGA
基于数据补偿
三、事务详解
3.1 刚 性 事 务 — — X A
(1)为了解决分布式事务一致性问题,X/Open组织提出了一套名为X/Open XA(XA的缩写为: eXtended Architecture)的处理事务架构,其核心内容是定义了全局的
事务管
(
Transaction Manager
,用于协调全局事务)和局部的
资源管理器
(
Resource Manager
,用于驱动本地事务)之间的通信接口。XA接口是双向的,能在一个事务管理器和多个资源管理器之间形成通信桥梁,通过协调多个数据源的一致动作,实现全局事务的统一提交或统一回滚。
(2)XA并不是Java的技术规范(XA提出的时候Java还没有诞生),而是一套跟语言无关的通用规范,所以Java中专门定义了JSR 907 Java Transaction API,基于XA模式在Java语言中实现了全局事务处理的标准,这也就是我们现在熟知的JTA(Java Transaction API)。
(3)JTA最主要的两个接口如下所示:
① 事务管理器接口(javax.transaction.
TransactionManager
)
② 满足XA规范的资源定义接口(javax.transaction.xa.
XAResource
)
3.2 刚 性 事 务 — — 2 P C
为了保证整个事务的一致性,XA将事务提交拆分成
两阶段
,即:二段式提交
(2 Phase Commit,2PC)协议。交互时序示意图如下所示:
2PC的缺点:
单点问题
性能问题
一致性风险
3.3 刚 性 事 务 — — 3 P C
为了缓解2PC中
协调者的单点问题
和
准备阶段的性能问题
,后续发展出了“三段式提交”,
即:3PC协议。交互时序示意图如下所示:
3PC把原本2PC中的
准备阶段
再细分为两
个阶段,即:
CanCommit阶段和
PreCommit阶段
。把
提交阶段
改称为
DoCommit阶段
。如下图所示:
3.4 柔 性 事 务 — — 可 靠 事 务 队 列
以快捷支付为例,当用户下单的时候,自动就进行了支付扣款操作。那么创建订单、扣
减库存和支付扣款这三个操作就应该是一个原子性的操作。那么如果我们采取可靠事件
队列的方式,则流程如下所示:
3.5 柔 性 事 务 — — T C C
TCC是“Try-Confirm-Cancel”的缩写,是常见的分布式事务机制。在具体实现上,TCC较
为繁琐,它是一种业务侵入式较强的事务方案,要求业务处理过程必须拆分为“
预留业务资源
”
和“
确认/释放消费资源
”两个子过程。
1、
Try(尝试执行阶段)
完成所有业务可执行性的检查(保
障一致性),并且预留好全部需要
用到的业务资源(保障隔离性)。
2、
Confirm(确认执行阶段)
直接使用Try阶段准备的资源来完成
业务处理。
Confirm阶段可能会重复执行,因此
本阶段执行的操作需要具备幂等性。
3、
Cancel(取消执行阶段)
释放Try阶段预留的业务资源。Cancel阶段可能会重复执行,因此
本阶段执行的操作需要具备幂等性。
3.6 柔 性 事 务 — — S A G A
1、SAGA事务:把一个大事务分解为可以交错运行的一系列子事务集合。原本SAGA的目的
是避免大事务长时间锁定数据库资源,后来才发展成将一个分布式环境中的
大事务分解
为一系列本地事务
的设计模式。
2、与TCC相比,SAGA不需要为资源设计冻结状态和撤销冻结的操作,补偿操作往往要比冻
结操作容易实现的多。
3、SAGA必须保证所有子事务都得以提交或者补偿,但SAGA系统本身也有可能会崩溃,所
以它必须设计成与数据库类似的
日志机制
(被称为SAGA Log)以保证系统恢复后可以追
踪到子事务的执行情况,比如执行到哪一步或者补偿到哪一步了。
3.7 柔 性 事 务 — — 基 于 数 据 补 偿
目录
1、seata的AT模式就是基于数据补偿来代替回滚思路的。
2、AT事务是参照了XA两段提交协议实现的,但是AT并不需要等待所有数据源都返回成功采取执
行全局提交,而是
通过了拦截SQL的方式,生
成前后镜像,生成行锁,通过本地事务一起提
交到操作的数据源中,相当于自己记录了重做
和回滚日志
。
3、如果分布式事务成功提交,那后续清理每个数据源中对应的日志数据即可;如果分布式事务
需要回滚,就根据日志数据自动产生同用于补
偿的“逆向SQL”。