Seata是如何处理空补偿和悬挂问题的?
Seata 通过引入 全局事务控制表(如 tcc_fence_log)和 状态校验机制 系统性解决 TCC 模式下的空补偿与悬挂问题,其核心设计如下:
一、空补偿(空回滚)解决方案
- 问题场景
当分支事务的 Try 阶段未执行(如网络超时或服务宕机),但全局事务触发回滚调用 Cancel 方法,导致无效回滚操作。
- Seata 处理流程
Try 阶段:
执行业务 SQL 前,向 tcc_fence_log 表插入记录,标记事务状态为 trying(与业务操作在同一个本地事务中提交)。
INSERT INTO tcc_fence_log (xid, branch_id, status)
VALUES ('全局事务ID', '分支事务ID', 'trying');
Cancel 阶段:
检查 tcc_fence_log 中是否存在对应 xid + branch_id 的 trying 记录:
存在记录 → 执行正常回滚逻辑(释放资源)。
不存在记录 → 判定为空回滚,跳过业务回滚并插入 suspended 状态记录(防悬挂)。
二、悬挂问题解决方案
- 问题场景
Cancel 先于 Try 执行(如 Try 请求延迟到达),导致 Try 操作误执行,预留资源无法释放。
- Seata 处理流程
Try 阶段前校验:
查询 tcc_fence_log 是否存在相同 xid + branch_id 的 suspended(空回滚标记)或 cancelled 记录。
存在记录 → 判定为悬挂,拒绝执行 Try 并抛出异常。
无记录 → 正常执行 Try 并插入 trying 记录。
状态闭环设计:
事务结束时(Confirm/Cancel 成功)插入终态记录(committed/cancelled),阻断滞后 Try 请求。
三、技术实现关键点
机制 实现方式 作用
事务状态表 创建 tcc_fence_log 表,字段包括 xid、branch_id、status 持久化事务状态,支持前置校验
注解驱动 使用 @TwoPhaseBusinessAction(useTCCFence = true) 启用防悬挂 自动注入状态校验逻辑
本地事务绑定 Try/Cancel 操作与状态记录插入在同一个本地事务中提交 确保状态与业务操作的原子性
终态屏障 Confirm/Cancel 成功后插入 committed/cancelled 记录 防止历史请求干扰
四、操作流程对照表
步骤 空回滚防护机制 悬挂防护机制
Try 前 - 检查是否存在 suspended/cancelled 记录
Try 中 插入 trying 记录 插入 trying 记录
Cancel 前 检查是否存在 trying 记录 -
Cancel 后 若空回滚则插入 suspended 记录 插入 cancelled 记录
典型案例:
电商扣库存场景:
防空回滚:库存服务 Cancel 时,校验到无 trying 记录 → 跳过回滚并标记 suspended。
防悬挂:后续延迟的 Try 请求发现 suspended 记录 → 拒绝执行并告警。
通过事务状态表的前置检查与状态闭环,Seata 在 1.5+ 版本 彻底解决了 TCC 模式的异常场景。
Seata 在 1.5+ 版本 在分布式事务管理上的多项关键改进
Seata 1.5+ 版本在分布式事务管理上进行了多项关键改进,涵盖稳定性、功能扩展和易用性提升,具体如下:
一、TCC 模式增强
解决三大核心问题:
空回滚:通过 tcc_fence_log 表校验 Try 状态,未执行 Try 的 Cancel 自动跳过并标记 suspended。
悬挂:Try 执行前检查是否存在 suspended 或 cancelled 记录,拦截滞后请求。
幂等性:Confirm/Cancel 操作通过事务状态表实现自动去重。
注解 @TwoPhaseBusinessAction(useTCCFence = true) 可一键启用防护。
二、控制台与监控增强
可视化控制台:
提供事务状态实时查看、事务链路追踪、全局锁查询等功能,支持运维人员快速定位问题。
SkyWalking 集成:
支持分布式事务链路与 SkyWalking 的 Tracing 数据联动,实现全链路性能分析。
三、通信协议扩展
支持多样化 RPC 协议:
新增 bRPC(字节跳动 RPC 框架)和阿里云 EDAS HSF 协议支持,适配混合云环境。
Kotlin 协程支持:
优化异步事务处理能力,提升高并发场景下的资源利用率。
四、性能与架构优化
全局锁机制重构:
减少锁竞争开销,提升 AT 模式在高并发下的吞吐量。
异步任务调度优化:
引入 distributed_lock 表管理任务调度,避免多节点任务冲突。
distributed_lock 表结构:
CREATE TABLE IF NOT EXISTS `distributed_lock` (
`lock_key` CHAR(20) NOT NULL COMMENT '锁键(唯一标识资源)',
`lock_value` VARCHAR(20) NOT NULL COMMENT '持有者标识(如服务节点ID)',
`expire` BIGINT NOT NULL COMMENT '过期时间戳(毫秒)',
PRIMARY KEY (`lock_key`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;