XA规范协议
基本介绍
在讲解Seate中的XA模式之前我们先来了解了解什么是XA规范。XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范描述了全局的TM与局部的RM之间的接口,XA 规范 在上世纪 90 年代初就被提出。目前,几乎所有主流的数据库都对 XA 规范 提供了支持。
XA 规范使用两阶段提交(2PC,Two-Phase Commit)来保证所有资源同时提交或回滚任何特定的事务。
它不是一个网络协议而是定义了 事务管理器(Transaction Manager)、应用程序(Application Program) 和 资源管理器(Resource Manager) 之间交互的 CAPI(Common Application Programming Interface) 接口标准
分布式事务处理模型角色
DTP(Distributed Transaction Processing)模型定义如下角色:
- AP:即应用程序,可以理解为使用DTP分布式事务的程序
- RM:资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库的实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务
- TM:事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理实务生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。
DTP模式定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接口协议,基于数据库的XA协议来实现的2PC又称为XA方案。
两阶段提交
俩阶段分为 准备阶段 和 提交阶段,它对分布式事务管理的流程如下
- 准备阶段:AP与TM交互,开启一个 全局分布式事务,并发送请求到每个RM,执行数据变更逻辑,此时每个RM会向TM发送请求注册 分支事务,在执行完业务逻辑后报告准备提交的状态(事务执行完未提交),之后AP会根据RM的响应在 提交阶段 做出反馈
- 提交阶段:如果所有的RM都回复“是”,表示它们已经准备好提交,那么AP会在该阶段向TM发出提交请求,分布式事务提交;否则,AP会向TM发出中止请求,分布式事务回滚
案例解释:
应用程序(AP)持有商品库和余额库两个数据源。
应用程序(AP)通过TM通知余额库(RM)和商品库(RM),来创建订单和减余额,RM此时未提交事务,此时商品和余额资源锁定。
如果TM收到执行回复,只要有一方失败则分别向其他RM发送回滚事务,回滚完毕,资源锁释放。
如果TM收到执行回复,全部成功,此时向所有的RM发起提交事务,提交完毕,资源锁释放。
Seata的XA的模式
基本介绍
我们都知道在Seata中有三个核心角色:事务管理器(Transaction Manager)、资源管理器(Resource Manager) 和 事务协调者(Transaction Coordinator)。
- TC (Transaction Coordinator) -事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
- TM (Transaction Manager) -事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) -资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
但是,在Seata中三个角色的定义与XA协议标准中角色的定义有所区别:
事务管理器(Transaction Manager)应该对应XA协议中的应用程序(Application Program)
事务协调者(Transaction Coordinator)对应XA协议中的事务管理器(Transaction Manager)
在Seata对原始的XA模式做了简单的封装和改造,以适应自己的事务模型,基本架构如图:
RM一阶段的工作:
① 注册分支事务到TC
② 执行分支业务但不提交
③ 报告执行状态到TC
TC二阶段的工作:
- TC检测各分支事务执行状态
a.如果都成功,通知所有RM提交事务
b.如果有失败,通知所有RM回滚事务
RM二阶段的工作:
- 接收TC指令,提交或回滚事务
具体使用
修改application.yml文件(每个参与事务的微服务),开启XA模式:
seata: data-source-proxy-mode: XA
给发起全局事务的入口方法添加@GlobalTransactional注解:
@GlobalTransactional @Transactional(rollbackFor = Exception.class) public void saveOrder(OrderSaveParam orderSaveParam) { // 参数校验等必要操作 // ... // 修改库存 reduceGoodsCount(goodsCountMap); // 扣除余额 reduceMoney(id,money); // 异常回滚事务 int i = 1 / 0; }
小结
性能:低
模式:CP,强一致性
难易程度:简单,基于数据库自带特性实现,无需改表
应用场景:金融行业,并发量不大,但数据很重要的项目
优点:
- 事务的强一致性,满足ACID原则。
- 常用数据库都支持,实现简单,并且没有代码侵入
缺点:
- 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
- 依赖关系型数据库实现事务
- 死锁(协议阻塞):XA prepare 后,分支事务进入阻塞阶段,收到 XA commit 或 XA rollback 前必须阻塞等待。如果没有一个靠谱的协调者存在,比如abc三个库的数据被二阶段决议为提交,此时ab收到的指令,提交后,c库在收到指令后挂了,并没有提交xa事务,或者协调者没有做到二阶段重试,那么这个没有提交的xa事务将会一直 持有锁,造成死锁的局面
- 性能差:性能的损耗主要来自两个方面:一方面,事务协调过程,增加单个事务的 RT;另一方面,并发事务数 据的锁冲突,降低吞吐。其实主要原因就是上面的阻塞跟数据锁定造成,因为xa的一阶段并非提交,如果一阶段都是提交的场景下,由于At模式的一阶段提交,at的性能是优于xa,因为它锁在tc一侧集中释放,无需多个库进行本地的锁释放