半步多 玄玉的博客

分布式事务01之事务详解及Seata浅尝

2020-08-06
玄玉

分布式事务是啥

高并发场景下的分布式事务,是行业内至今没有很好解决的难题

其核心点在于:事务参与者出现在不同的数据库实例,需要网络通讯进行交互,引发了分布式场景下数据一致性问题

以购物下单的场景来分析

当订单表和库存表都在一个 DB 实例时,那么一个本地事务就能保证 ACID

而订单和库存分处于不同的 DB 实例时,那么下单的过程中,生成订单是一个事务参与者,减库存是一个事务参与者

在它俩的上面还有一个模块,负责先创建订单再减库存(或先锁库存再创建订单,谁先谁后,视业务场景而定)

但由于是不同的 DB 实例,原子性被破坏了,也就无法保证 ACID,这就是分布式事务产生的背景

其实就是把库拆开了,原来的一个操作一次事务可以在一个 DB 里完成,现在在两个 DB 里了

而我们还需要保证它的事务(也就是保证数据的一致,要么全成功,要么全失败),这就是分布式事务

分布式事务分类

分布式事务在不同的一致性要求上,通常有不同的解决方案(这玩意儿终究没有银弹)

一般分两种:强一致(刚性事务)和最终一致(柔性事务)

比如ABC三个操作,刚性事务就要求三个必须同时全成功或全失败(不允许落单)

而柔性事务则不同,比如AB写入成功,C失败,这时就不会要求它全成功,或者说没必要在同一时刻全成功

失败的那个可以通过线下或离线的机制让它成功,这样业务上体验会好一点,毕竟希望该交易是成功的,这就是柔性事务

不过柔性事务也不一定都是奔着成功走的,后面补充处理时也可能让AB都回滚,反正最终数据是对齐的,不会出现不一致

  刚性事务 柔性事务
分类 XA、2PC、3PC TCC、Saga、事务消息、最大努力通知事务
一致性 强一致 最终一致
隔离性 原生支持 实现资源锁定接口
适合场景 短事务,并发较低 长事务,高并发
并发性能 严重衰退 略微衰退
业务改造

刚性事务

我们说的刚性事务,基本上就可以认为是XA,它基于2PC协议,各数据库厂商都实现了XA规范(实际上干的就是两阶段的事)

它是根据 XA 接口做真正的写入操作,但不提交,最后有一个事务管理器去协调通知它们提交,在此期间数据就被锁住了

其它事务或人就不能用了,性能损耗极大,并且刚性事务的时间大部分都耗在数据库上了,也就不太适合互联网

不过,改造起来比较简单:把以前调用普通数据源的地方,改成调用 XA 的数据源就行了

另外,XA的事务管理器会将事务执行状态记录在 local-log,即它是有状态的,若机器崩了那状态也就没了,故其不支持高可用

柔性事务

TCC:该模型等于是完全交给业务了,需要开发同学自己实现Try、Confirm、Cancel,业务入侵比较大
   Try:资源的检测和预留,比如转账,先保证 A 账户余额足够并冻结
   Confirm:执行业务操作,若 Try 成功 Confirm 一定要能成功(即执行 A 账号预留资源的扣款)
   Cancel: 对 Try 资源预留的释放(即执行第一阶段资源的释放,解冻 A 账号预留的余额)

Saga:它是基于异步补偿的模型,业务实现时需要写正向和逆向两个接口的操作,业务入侵比较大
    失败时,事务调度器会调正向补偿(最后让它全部成功),或调逆向操作回滚事务

事务消息:保证本地DB和发MQ这俩操作的原子性(另一个DB会去消费该MQ),但它不能保证另一个DB消费成功还是失败
     所以它只做了一半(只保证了自己这块),它不是一个完全的分布式事务

最大努力通知事务:它可以基于Saga来做,就是说不逆向回滚,直接正向补偿,多试几次,尽最大努力让这个事务成功

一般可以选择 TCC 或 Saga(他俩的一致性基本是一样的),如果对一致性要求没有那么高,就可以用事务消息

事务模式对比

性能损耗:XA > TCC = Saga = 事务消息

一致性保障:XA > TCC = Saga > 事务消息

业务友好性:XA > 事务消息 > Saga > TCC

Seata简述

Seata:Simple Extensible Autonomous Transaction Architecture,简单可扩展自治事务框架

Seata 的愿景就是像使用本地事务一样使用分布式事务,目标是提供一站式的分布式事务解决方案

它的演进历史是这样的:

  1. TXC(Taobao Transaction Constructor):阿里巴巴中间件团队 2014 年启动该项目,以解决分布式事务的问题
  2. GTS(Global Transaction Service):2016 年 TXC 作为阿里中间件的产品,更名为 GTS 发布
  3. Fescar(Fast & EaSy Commit And Rollback):2019年01月09号基于阿里商用版的 GTS 开源了 Fescar
  4. Seata:随着蚂蚁金服的加入并贡献了 TCC 模式,更名为 Seata,地址为 https://github.com/seata/seata

它具有以下特性

  • 支持多个微服务框架:Dubbo、SpringCloud、Sofa-RPC、Motan、gRPC
  • 高可用:支持基于数据库存储的集群模式,水平扩展能力强
  • 高可扩展性:支持配置中心、注册中心、SPI扩展

其缺点是不保证隔离性(事实上,业界的分布式事务解决方案中,一致性是优先保障的,隔离性几乎很少能完全做到)

并且,Seata要求数据库必须是支持本地 ACID 事务的关系型数据库,且必须定义主键

Seata事务模式

它支持以下四种事务模式

  • AT模式:原始支持,早期还有MT模式(0.4.2废弃)
  • TCC模式:0.4版本支持,2019.03.19
  • Saga模式:0.9版本支持,2019.10.16
  • XA模式:1.2版本支持,2020.04.21

其中 AT(Automatic Transaction)模式是 Seata 独有的,好处在于:业务不需关心事务,只关注自己的逻辑SQL就行了

使用 AT 模式就类似于在使用 XA 模式,而它的性能衰减更友好一些,没有 XA 这么大

从业务侵入的角度来看:AT 和 XA 无侵入,TCC 和 Saga 有侵入

Seata核心框架

它主要由Transaction Coordinator(TC)、Transaction Manager(TM)、Resource Manager(RM)三个模块组成

TC:事务协调者。维护全局和分支事务的状态,负责协调并驱动全局事务的提交或回滚
   TC 不存在单点问题,它的数据是存到数据库的,它是无状态的,可以做到高可用
   并且 TC 的数据量并不大,它自己的事务就用本地事务就行了,它不用再搞一个分布式事务,也不用跨数据中心

TM:事务管理器。控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议

RM:资源管理器。控制分支事务的边界和行为,负责分支注册、状态汇报,并接收 TC 指令,驱动分支(本地)事务的提交或回滚
   RM 做的事就是在业务 SQL 基础上做一层拦截,然后想干啥干啥

全局事务就是对若干分支事务的整体协调,一个典型的事务过程包括:

  1. TM 向 TC 申请开启一个全局事务,TC 创建全局事务后返回全局唯一的 XID,XID 会在全局事务的上下文中传播
  2. RM 向 TC 注册分支事务,该分支事务归属于拥有相同 XID 的全局事务
  3. TM 向 TC 发起针对 XID 的全局提交或回滚
  4. TC 调度 XID 下的全部分支事务完成提交或回滚

基于架构上定义的这三个核心组件,分布式事务被抽象成如下事务框架:

这个框架图非常重要,理解了他,再去理解后面文章中介绍的四种事务模式就易如反掌了

Seata 的四种事务模式都是在该框架里跑的,不同事务模式体现在 RM 内部实现的方式不同

换句话说:该框架下 RM 驱动的分支事务的不同行为模式,即事务(分支)模式

补充

Seata 的 TCC 和 Saga 没有什么性能衰减,主要衰减还是在业务上

只是 AT 上衰减比较严重,后来 AT 把上报分支事务状态的步骤给取消了,这又提升了不少性能(但也相应的带来一些流程的改造)


相关文章

上一篇 白话领域驱动

Content