|---|---
id| bigint(20)| PRI
name| varchar(100)|
since| varchar(100)|
AT 分支事务的业务逻辑:
update product set name = 'GTS' where name = 'TXC';
执行阶段
过程:
- 解析 SQL:得到 SQL 的类型(UPDATE),表(product),条件(where name = ‘TXC’)等相关的信息。
- 查询前镜像:根据解析得到的条件信息,生成查询语句,定位数据。
select id, name, since from product where name = 'TXC';
得到前镜像:
id | name | since |
---|---|---|
1 | TXC | 2014 |
- 执行业务 SQL:更新这条记录的 name 为 ‘GTS’。
- 查询后镜像:根据前镜像的结果,通过 主键 定位数据。
select id, name, since from product where id = 1`;
得到后镜像:
id | name | since |
---|---|---|
1 | GTS | 2014 |
- 插入回滚日志:把前后镜像数据以及业务 SQL 相关的信息组成一条回滚日志记录,插入到
UNDO_LOG
表中。
{
"branchId": 641789253,
"undoItems": [{
"afterImage": {
"rows": [{
"fields": [{
"name": "id",
"type": 4,
"value": 1
}, {
"name": "name",
"type": 12,
"value": "GTS"
}, {
"name": "since",
"type": 12,
"value": "2014"
}]
}],
"tableName": "product"
},
"beforeImage": {
"rows": [{
"fields": [{
"name": "id",
"type": 4,
"value": 1
}, {
"name": "name",
"type": 12,
"value": "TXC"
}, {
"name": "since",
"type": 12,
"value": "2014"
}]
}],
"tableName": "product"
},
"sqlType": "UPDATE"
}],
"xid": "xid:xxx"
}
- 提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁 。
- 本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
- 将本地事务提交的结果上报给 TC。
完成阶段-回滚
-
收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
-
通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
-
数据校验:拿 UNDO LOG
中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理,详细的说明在另外的文档中介绍。 -
根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
update product set name = 'TXC' where id = 1;
- 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。
完成阶段-提交
- 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
- 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。
和 XA 的关系
前面一直拿 AT 和 XA 做比较。
这里特别说明一下,并不是说 XA 协议本身有问题,只是说在某些场景的需求下,基于 XA 做不理想。
但同样,另外还有一些对内外部 一致性要求非常高 的场景,可能 XA 又是非常适合,甚至必需的。
这也是接下来 Seata 将提供 XA 模式的原因。
关于 XA 模式 这里就不展开了,后面会有专门的文章和大家交流。
AT 的核心价值
AT 模式到底带给我们什么价值呢?
首先,从技术原理角度来看,非常重要的一点是: 平衡 。

必须承认,分布式事务是个复杂的问题,目前还没有任何一种解决方案可以非常完美地适应所有应用场景。
如果把分布式事务方案按 一致性 、 性能 和 易用性 这 3 个维度来考量:AT
模式,实际上是在业务需求允许的前提下,找到一个比较好的平衡点。
编程模型不做改变的前提下,达到确定的一致性,而且保证了性能和系统可用性。
其次,从用户的角度来看。我们设想一个企业业务的成长过程:

-
1.0:单体应用,快速上线,这个时候完全不涉及分布式事务。
-
2.0:单个数据库无法支撑,数据分布到多个数据库,产生分布式事务问题。
-
3.0:微服务化,进一步产生跨服务的分布式事务。
-
4.0:跨应用的整合,成为 SaaS 或 FaaS 的平台,在更大的范围,产生分布式事务问题。
基于 Seata 的 AT 模式构建企业业务的分布式事务解决方案,可以带来以下 3 个方面的 核心价值 :
- 低成本 : 编程模型 不变,轻依赖 不需要为分布式事务场景做特定设计,业务像搭积木一样自然地构建成长。
- 高性能 :协议 不阻塞 ;资源释放快,保证业务的吞吐。
- 高可用 :极端的异常情况下,可以暂时 跳过异常事务 ,保证整个业务系统的高可用。
AT 的现在和未来
没有 银蛋 ,AT 模式带来上面提到的价值的同时,也必定有一些局限和不足。
较重的 SDK

AT 模式有很大一部分功能依赖于 SDK 的实现,包括 SQL 解析、回滚日志的生成、分支提交回滚逻辑的执行等等。
这些关键运行机制是基于 Java 的 JDBC 构建起来的。如果要支持其他语言,迁移成本非常高。
面向云原生时代,AT 模式未来的方向将是 SDK 的轻量化和标准化,把大部分能力下沉到代理层(Agent 或 Sidecar 的形式),让应用只需要很简单的
SDK 和标准的 SQL 就可以工作。

能力边界
从工作原理来看,AT 模式有一些特定的使用条件和局限。
首先,AT 模式的 基本条件 是:数据库本身必须支持 本地事务 。AT 的基本工作机制是基于本地事务的。
其次,数据表必须定义 主键 。回滚日志的生成和使用,是基于数据主键的。
另外, 隔离性 ,这也是所有基于 补偿
的分布式事务解决方案,都面临的问题:隔离性很难做到很高,或者说,要做到较高隔离性的成本和收益是不匹配的。
基于这些目前的局限,Seata 项目整体的应对策略是,提供各类不同的事务模式来取长补短,实现全场景的覆盖。
目前已经具备和正在规划中的,一共是两大类,4 种事务模式:

-
业务无侵入的:AT、XA
-
业务侵入的:TCC、Saga
这些模式各自有其适用和不适用的场景,Seata 将把这些模式很好地融合起来,给用户提供一站式的解决方案。
总结
Seata 的 AT 模式是分布式架构演进过程中,分布式事务中间件在阿里巴巴实践的创造性解决方案。
Seata 的 AT 模式基于本地事务的特性,通过拦截并解析 SQL 的方式,记录自定义的回滚日志,从而打破 XA 协议阻塞性的制约,在一致性、性能、易用性
3 个方面取得平衡:在达到确定一致性(非最终一致)的前提下,即保障较高的性能,又能完全不侵入业务。
在绝大部分应用场景下,Seata 的 AT 模式都能很好地发挥作用,把应用的分布式事务支持成本降到极低的水平。
对于一些不适用 AT 模式的场景,Seata 也提供其他几类主流的分布式事务解决方案来补齐。
附录
- Seata 官网:http://seata.io/zh-cn/
- Seata on GitHub:https://github.com/seata/seata
- 支持 Seata AT 模式的阿里云 GTS(Global Transaction Service):https://www.aliyun.com/aliware/txc
作者:sharajava
链接:https://www.jianshu.com/p/0ed828c2019a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论区