孤舟笔记 分布式与微服务篇十五 Seata到底是怎么实现分布式事务的?AT模式原理一次讲透
Seata AT模式原理摘要(148字): Seata AT模式通过两阶段实现分布式事务:一阶段直接提交本地事务,同时记录SQL修改前后的数据快照到undo_log;二阶段根据结果决定删除日志(提交)或利用undo_log生成反向SQL回滚(before image恢复数据)。关键机制包括:SQL拦截自动生成undo_log、全局锁防止脏写、XID跨服务传播。相比TCC模式,AT模式只需添加@Gl
个人网站
前面讲了分布式事务的方案,Seata 是目前最主流的分布式事务框架,它的 AT 模式号称"业务零侵入"——怎么做到的?面试官问这题,他想听的是:你能不能讲清 AT 模式的一阶段/二阶段流程、undo_log 的原理、以及全局锁的作用?
先说结论
| 维度 | 说明 ||
| ------|------||
| 是啥 | 阿里开源的分布式事务框架 ||
| 核心组件 | TC(协调者)、TM(事务管理器)、RM(资源管理器) ||
| AT 模式 | 一阶段提交 + undo_log 回滚,业务零侵入 ||
| TCC 模式 | Try/Confirm/Cancel,需业务实现三接口 ||
| Saga 模式 | 正向+补偿链,长流程场景 ||
| 核心优势 | AT 模式无需改造业务代码 ||
|一句话记住:Seata AT模式像"带后悔药的提交"——先提交,后悔了用undo_log撤回"
三大核心角色
TC(Transaction Coordinator)事务协调者
├── 维护全局事务状态
├── 决定提交或回滚
└── 独立部署的 Seata Server
TM(Transaction Manager)事务管理器
├── 开启全局事务
├── 决定提交或回滚
└── 通常是发起方服务
RM(Resource Manager)资源管理器
├── 管理分支事务
├── 注册分支、上报状态
└── 每个参与服务都有一个
TM ──开启全局事务──→ TC ──返回XID──→ TM
TM(带XID) ──调服务A──→ RM_A ──注册分支──→ TC
TM(带XID) ──调服务B──→ RM_B ──注册分支──→ TC
TM ──提交/回滚──→ TC ──通知各RM──→ RM_A, RM_B
AT 模式:一阶段提交
AT 模式的核心是 一阶段就直接提交本地事务,不像 2PC 那样锁住资源等待。
一阶段流程:
// 业务代码,完全不用改!
@GlobalTransactional // 👈 只加这个注解
public void purchase(String userId, String commodityCode, int count) {
orderService.create(userId, commodityCode, count); // 订单服务
stockService.deduct(commodityCode, count); // 库存服务
accountService.debit(userId, totalAmount); // 账户服务
}
Seata 在 SQL 执行前后自动拦截:
-- 业务SQL:扣减库存
UPDATE stock SET count = count - 10 WHERE commodity_code = 'C001';
-- Seata 自动做的事:
-- 1. 执行前:查询修改前的数据(before image)
SELECT count FROM stock WHERE commodity_code = 'C001'; -- before: 100
-- 2. 执行业务SQL
-- 3. 执行后:查询修改后的数据(after image)
SELECT count FROM stock WHERE commodity_code = 'C001'; -- after: 90
-- 4. 生成 undo_log 记录
INSERT INTO undo_log (branch_id, xid, rollback_info) VALUES (
1, 'xxx',
'{"beforeImage":{"count":100}, "afterImage":{"count":90}, "sqlType":"UPDATE"}' 👈
);
-- 5. 提交本地事务(业务数据 + undo_log 一起提交)
COMMIT;
关键点:本地事务直接提交了!不用等其他服务。这就是 AT 模式高性能的原因。
AT 模式:二阶段
提交:因为一阶段已经提交了,二阶段只需删除 undo_log。
回滚:读取 undo_log 中的 before image,生成反向 SQL 回滚:
-- undo_log 中的 before image: count = 100
-- 生成反向SQL:
UPDATE stock SET count = 100 WHERE commodity_code = 'C001'; -- 👈 恢复原值
-- 删除 undo_log
DELETE FROM undo_log WHERE branch_id = 1 AND xid = 'xxx';
全局锁:防止脏写。一阶段提交后,其他全局事务要修改同一行数据,必须等当前事务提交或回滚后才能获取全局锁。
全局锁机制
事务A:扣库存 count=100→90,获得全局锁
事务B:也想扣库存,发现全局锁被A持有
→ 事务B等待(不是阻塞,是自旋重试) 👈
事务A提交 → 释放全局锁
事务B获得全局锁 → 继续执行
AT vs TCC vs Saga
| 对比 | AT | TCC | Saga ||
| ------|-----|-----|------||
| 侵入性 | 零(只加注解) | 高(三个接口) | 中(正向+补偿) ||
| 一致性 | 最终一致 | 最终一致 | 最终一致 ||
| 性能 | 高(一阶段提交) | 高 | 最高 ||
| 隔离性 | 全局锁(读已提交) | 业务隔离 | 无隔离 ||
| 适用 | 常规业务 | 资金类 | 长流程 ||
Seata 全景
核心角色
├── TC —— 事务协调者(Seata Server)
├── TM —— 事务管理器(发起方)
└── RM —— 资源管理器(参与方)
AT模式流程
├── 一阶段 → 拦截SQL + before/after image + undo_log + 本地提交
├── 二阶段提交 → 删除undo_log
└── 二阶段回滚 → 读undo_log + 生成反向SQL + 恢复数据
关键机制
├── undo_log → 回滚依据
├── 全局锁 → 防脏写
└── XID传播 → 跨服务事务关联
口诀:一阶段拦截SQL,前后快照存undo;
本地事务直接提,不用等别人完成;
二阶段提交删日志,回滚用反向SQL;
全局锁防脏写,业务代码零改造
回答技巧与点评
标准回答:Seata 是阿里开源的分布式事务框架,核心组件有 TC(协调者)、TM(管理器)、RM(资源管理器)。AT 模式实现零侵入:一阶段拦截 SQL,记录修改前后的数据快照到 undo_log,直接提交本地事务;二阶段提交时删 undo_log,回滚时根据 undo_log 生成反向 SQL 恢复数据。通过全局锁防止脏写,通过 XID 传播关联跨服务事务。
加分回答
- undo_log 的脏检查:回滚时 Seata 会对比当前数据和 after image,如果不一致说明被其他事务修改了,需要人工介入。这是 AT 模式的安全兜底
- Seata 的性能优化:Seata 1.5+ 引入异步提交(二阶段异步删除 undo_log),减少同步等待时间。还支持读写隔离级别的配置,读操作可以不加全局锁
- Seata 的局限:AT 模式只支持关系型数据库(需要解析 SQL 生成 undo_log);全局锁是性能瓶颈(高并发场景下锁竞争严重);不支持嵌套全局事务
面试官点评
这道题考的是你对 主流分布式事务框架 的理解。最忌讳的回答是"Seata 就是加个 @GlobalTransactional"——面试官想听的是 AT 模式的底层原理:怎么拦截 SQL、undo_log 怎么用、全局锁怎么防脏写。能把一阶段二阶段流程讲清楚,再说出 undo_log 的脏检查机制,就是高分回答。
内容有帮助?点赞、收藏、关注三连!评论区等你 💪
更多推荐




所有评论(0)