导航
- 一、Seata 介绍
- 二、Seata 的工作原理
- 2.1 三个角色
- 2.2 工作流程
- 三、Seata AT 工作机制
- 3.1 一阶段
- 3.2 二阶段
- 四、案例演示(待补充)
一、Seata 介绍
官网:Seata 官网
Seata 是2019 年阿里巴巴中间件团队发起的开源项目,其前身是 Fescar(Fast & EaSy Commit And Rollback)。其愿景是让分布式的使用像本地事务的使用一样简单、高效,并逐步解决开发者遇到的分布式事务方面的所有难题。
Seata 意为 Simple Extensible Autonomous Transaction Architecture,简单可扩展自治分布式框架。
Seata 的设计目标是对业务无侵入,因此从业务无侵入的 2PC 方案入手,在传统 2PC 的基础上扩展,把一个分布式事务理解成一个包含若干分支事务的全局事务
二、Seata 的工作原理
2.1 三个角色
1、TC:Transaction Coordinator 事务协调器,管理全局的分支事务状态,用于全局性事务的提交和回滚。
2、TM:Transaction Manager 事务管理器,用于开启、提交或回滚全局事务。
3、RM:Resource Manager 资源管理器,用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或回滚分支事务。
2.2 工作流程
假设上图中的三个服务根据调用关系为 A–> B–>C,那么 Seata 的执行流程如下:
1、A 服务的TM 向TC申请开启一个全局事务,TC会创建一个全局事务并返回一个 唯一的 XID。
2、A 服务的 RM向 TC注册分支事务,并将其纳入 XID 对应全局事务的管辖。
3、A 服务执行分支事务,操作数据库。
4、A 服务开始远程调用 B 服务,此时XID 会在微服务的调用链上传播。
5、B 服务的 RM 向TC 注册分支事务,并将其纳入 XID 对应的全局事务的管辖。
6、B 服务执行分支事务,操作数据库。
7、全局事务调用链处理完毕,TM 根据有无异常向 TC 发起全局事务的提交或回滚。
8、TC 协调其管辖下的所有分支事务,决定是否回滚。
Seata 实现 2PC 与传统 2PC 的区别:
1、架构层次方面,传统 2PC 方案的 RM 实际上是在数据库层,RM 本质就是数据库,通过 XA 协议实现,而 Seata 的 RM 是以 jar 包的形式作为中间件层部署在应用程序这一侧的。
2、两阶段提交方面,传统 2PC 无论第二阶段的决议是 commit 还是 rollback ,事务性资源的锁都要保持到 Phase 2 完成才释放。而 Seata 的做法是在 Phase 1 就将本地事务提交,这样就可以省去 Phase 2 持锁的时间,整体提高效率。
三、Seata AT 工作机制
Seata 在 2PC 提交模型的基础上进行了演进,视为 Seata AT 模式。除此之外,还有 Seata TCC模式、Seata XA 模式等。
Seata AT 模式非常简单,也是两阶段提交。
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:- 异步提交,快速完成;- 回滚,通过一阶段回滚日志进行反向补偿。
下面以一个简单示例说明整体 AT 模式的工作机制,参考原文:Seata AT 模式
3.1 一阶段
商品表:product :
Field | Type | Key |
---|---|---|
id | bigint(20) | PRI |
name | varchar(100) | |
since | varchar(100) |
业务逻辑:
update product set name = 'GTS' where name = 'TXC';
1、解析SQL:得到 Sql 类型(update),表(product),条件等信息。
2、查询前镜像:根据解析得到的条件,生成查询语句,定位数据:
select id, name, since from product where name = 'TXC';
id | name | since |
---|---|---|
1 | TXC | 2014 |
3、执行业务 SQL:更新这条记录的 name 为 ‘GTS’。
4、查询后镜像:根据前镜像的结果,通过 主键 定位数据。
select id, name, since from product where id = 1;
id | name | since |
---|---|---|
1 | GTS | 2014 |
5、插入回滚日志:把前后镜像数据以及业务 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"
}
6、提交前,向 TC 注册分支:申请 product 表中,主键值等于 1 的记录的 全局锁 。
7、本地事务提交:业务数据的更新和前面步骤中生成的 UNDO LOG 一并提交。
8、将本地事务提交的结果上报给 TC。
3.2 二阶段
回滚
1、收到 TC 的分支回滚请求,开启一个本地事务,执行如下操作。
2、通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
3、数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理,详细的说明在另外的文档中介绍。
4、根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句:
update product set name = 'TXC' where id = 1;
5、提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。
提交
1、收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
2、异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。
四、案例演示(待补充)
演示一个电商下订单扣库存的应用案例,看下 Seata 是如何使用的。