分布式事务与Seata

分布式事务DTP模型

DTP模型是Distributed Transaction Processing的缩写,DTP是一套分布式事务的规范,不同的厂商针对此规范提供实现。DTP中包含AP、RM、TM三个角色,其中:

  • AP(Application Program):应用程序,就是我们使用分布式事务的应用;
  • RM(Resource Manager):资源管理器,表示参与分布式事务的资源,比如数据库,MQ等;
  • TM(Transaction Manager):事务管理器,是分布式事务的协调者。

它们之间的关系如下:

image

在DTP模型中,AP操作RM完成事务中的数据操作,比如数据库的更新等,在这些操作结束后,AP通过TX接口向TM发起提交事务或者回滚事务,TM通过XA协议向RMs提交或者回滚事务,XA通过两阶段提交的方式完成事务的提交或回滚。

DTP和XA的缺点:

  • 缺少事务补偿机制,2PC有数据不一致的风险,如果多个RM只有一部分提交成功,其它RM在提交事务时出现超时等错误,无法进行事务的补偿,会造成数据不一致
  • XA协议会导致资源的阻塞,在整个事务的过程中,RM资源会一直被事务持有,直到事务提交或回滚
  • 性能非常低
  • 并不是所有资源都支持XA协议,mysql5.7以前的版本对XA的支持不太好

两阶段提交(2PC)

前面说过XA协议通过两阶段提交的方式做事务的提交或回滚,两阶段提交,即将事务的提交分为两个阶段:

  • 第一阶段:prepare阶段,用于向RM询问事务是否可提交,至于RM如何实现prepare则完全靠RM,比如记录redo和undo日志
  • 第二阶段:commit/rollback,如果所有RM的prepare执行后都表示可以提交,则依次commit,否则依次rollback

两阶段提交的示意图可表示如下:

image

如果有RM的prepare阶段失败,则需要回滚,示意图如下:

image

2PC的缺点:

  • 整个事务过程中,所有资源都是阻塞式持有
  • 性能差
  • 会有数据的不一致风险,当有部分资源提交成功部分不成功时,数据不一致
  • TM容易成为逻辑单点,当TM宕机,事务状态难以恢复

Seata对分布式事务的支持

image

这里先介绍三个概念:

  • 全局事务:表示一次分布式事务,由TM发起
  • 分支事务:每个RM都有一个事务,被称为分支事务
  • XID:全局事务的事务ID

Seata借鉴了DTP模型中的概念,并且自定义了TC(Transaction Coordinator)角色,实际上是将事务的协调者从TM中分享出来并独立部署,TC负责全局事务的提交和回滚,并对分支事务做补偿,使得即使事务提交过程各,部分分支事务成功部分失败,也能达到最终一致

Seata支持的分布式事务的模式

AT模式

AT模式是建立在数据库的ACID事务的基础上的,它提供的两阶段提交是对XA的两阶段提交的演进,效率上比XA好,但是整体开销还是偏大。AT模式的基础原理是在每个分支事务的数据库中记录事务的回滚日志,seata对事务的处理过程如下:

  • 开启全局事务,向TC获取事务ID

  • 依次执行分支事务

  • 开启分支事务

  • 通过解析sql的方式拿到sql的表、更新字段、条件等

  • 根据条件查询,获取到事务更新前的镜像

  • 执行更新

  • 再次查询,获取 到更新后的镜像

  • 通过后镜像生成redo log,插入到分支事务所在的库中

  • 提交分支事务前,先向TC注册分支事务,并获取操作的数据的id对应的全局锁,如果获取失败,全局锁被其它事务持有,则回滚

  • 提交分支事务,并向TC上报分支事务执行结果

  • 提交全局事务,释放全局锁

当事务需要回滚时,每个分支事务的DB中有redo log,RM通过redo log执行事务的回滚,但回滚时需要对数据进行判断,如果当前数据与redo log中的兵团镜像相同,则回滚,否则表示数据被事务外的操作修改了,需要根据配置策略做处理。AT模式下的两阶段提交行为如下:

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚

TCC模式

Seata支持TCC模式,TCC模式也是基于两阶段提交的,与AT模式不同的是,TCC不依赖数据库的ACID特性,而是依赖应用自定义的一阶段的prepare行为和二阶段的commit/rollback行为,TCC模式将事务从数据库层面提升到了应用服务层面。

在TCC模式中,分支事务需要实现prepare、commit和rollback三个方法,其示意图如下:

image

总体过程比较清晰:

  • TM开启全局事务,获取XID

  • 依次执行分支事务

  • 向TC注册分支事务

  • 执行事务的prepare阶段

  • 提交或者回滚全局事务,TC向每个RM发起commit或者rollback

TCC模式下,两阶段行为如下:

  • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
  • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
  • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

Saga模式

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

说简单点,就是第一阶段,每个分支事务先自己提交,当需要回滚的时候,分支事务提供一个回滚的入口,对事务做逆向过程:

image

Saga模式有一定的优势:

  • 参与者可异步执行
  • 性能高,一阶段提交本地事务
  • 补偿服务易于实现

AT、TCC、Saga三种模式的比较

  • AT模式:

  • AT模式的性能低,有全局锁,一次分支事务多一次SQL解析和两次查询一次插入,成本比本地事务高得多,这些DB操作是实现回滚的代价

  • 全局锁有死锁的风险

  • 保证了隔离性,全局锁能实现读隔离和写隔离,详情可以阅读seata的文档

  • 基于本地数据库的ACID特性,代码改造代价低

  • TCC模式:

  • 代码改造代价大,需要将事务拆分成prepare+commit并提供rollback

  • 性能好,不会阻塞资源

  • 将两阶段由应用自身定义,可达到较高的隔离性

  • Saga模式:

  • 代码改造代价比TCC模式小,但比AT模式大,需要提供回滚补偿接口

  • 性能好,第一阶段就提交了分支事务

  • 没有隔离性

AT、TCC、Saga三种模式,是在性能、改造成本、隔离性三者之间做权衡和取舍,AT选择了隔离性和低改造成本,TCC选择了性能和隔离性,Saga选择了性能和低改造成本,如下图所示:

image

基于事务消息的分布式事务方案

还可选择使用RocketMQ的事务消息来实现分布式事务。

优点:

  • 实现简单,改造成本小
  • 性能高,没有全局锁,也没有两阶段的开销

同样有缺点和限制:

  • 没有隔离性的支持
  • 弱一致,对于库存扣减类场景不适用
  • 事务消息一旦提交,全局无法回滚

如果采用事务消息实现分布式事务,需要有其它方案规避其缺点,这里不做描述。

你可能感兴趣的:(分布式事务与Seata)