SAGA 模式在使用方式上(如通过注解或配置定义事务)可能与 Seata 的 AT、TCC 模式看似相似,但它的设计目标和适用场景与其他模式有本质区别,尤其在「长事务」场景中具有不可替代的优势。以下从「SAGA 与其他模式的核心差异」「长事务的定义」「SAGA 为何适配长事务」三个层面展开说明。
一、SAGA 与其他模式的核心区别(为何专用于长事务)
Seata 的 AT、TCC 模式本质是「短事务」解决方案,而 SAGA 是「长事务」解决方案,核心差异体现在事务持续时间和资源锁定方式上:
| 模式 | 事务持续时间 | 资源锁定方式 | 适用场景 | 为何不适合长事务 |
|---|---|---|---|---|
| AT | 短(毫秒 / 秒级) | 全局锁 + 数据库锁(短时间持有) | 高频、短流程(如订单支付) | 锁持有时间长会导致并发阻塞,性能急剧下降 |
| TCC | 短(毫秒 / 秒级) | 业务层锁(如冻结资源) | 复杂业务逻辑(如跨境支付) | 冻结资源长期不释放,导致资源利用率极低 |
| SAGA | 长(分钟 / 小时级) | 无锁,依赖补偿机制 | 跨多系统、长流程(如物流调度) | 允许资源临时不一致,通过补偿最终一致 |
关键差异点:
- AT/TCC 依赖「锁机制」保证数据即时一致性,锁必须在短时间内释放(否则阻塞并发),因此只能处理短事务。
- SAGA 放弃锁机制,允许中间状态存在(如订单创建后未支付、库存临时超卖),通过「补偿操作」最终修复一致性,因此能支撑长时间运行的事务。
二、什么是「长事务」?
长事务指执行时间长(分钟、小时甚至天级)、涉及多个跨系统步骤的事务,典型场景如:
- 电商的「订单 - 支付 - 发货 - 签收 - 结算」全流程(可能持续数天)。
- 供应链的「采购申请 - 审批 - 供应商发货 - 入库 - 付款」流程(可能持续数周)。
- 金融的「贷款申请 - 征信 - 审批 - 签约 - 放款」流程(可能持续数天)。
这类事务的特点:
- 步骤多且分散在多个独立系统(如订单系统、物流系统、财务系统)。
- 步骤间可能存在人工干预(如审批、签收),导致整体耗时极长。
- 无法接受资源长期锁定(如订单未支付时,库存不能被锁几天)。
三、SAGA 模式为何适合长事务?
SAGA 模式通过状态持久化、补偿机制和无锁设计三大特性,完美适配长事务的需求:
1. 状态持久化:支持断点续跑
长事务可能因服务重启、网络中断等原因中断,SAGA 通过 saga_instance 和 saga_step_instance 表持久化事务状态,重启后可从断点继续执行:
java
运行
// 服务重启后,SAGA 引擎自动恢复未完成的事务
public class SagaRecoveryService {
@Autowired
private StateMachineEngine engine;
@Autowired
private SagaRepository repository;
@PostConstruct
public void recover() {
// 查询数据库中“运行中”或“失败”的事务实例
List<StateMachineInstance> instances = repository.findUnfinishedInstances();
for (StateMachineInstance instance : instances) {
// 从断点继续执行
engine.retry(instance.getId());
}
}
}
- 这是长事务的核心需求:即使中断数小时,也能恢复执行,无需从头开始。
2. 补偿机制:允许中间状态,最终一致
长事务中,步骤间可能间隔数小时(如用户下单后几小时才支付),无法通过锁保持资源一致性。SAGA 允许中间状态存在,若最终失败则通过补偿回滚:
- 例如:订单创建 → 库存预扣 → (2 小时后)支付失败 → 补偿(释放库存)。
- 补偿逻辑由业务代码定义(如
cancelOrderrefundStock),灵活处理各种中间状态。
3. 无锁设计:不阻塞并发,适合长时间运行
SAGA 不依赖全局锁或资源锁定,允许其他事务并发操作资源(如多个订单同时预扣同一商品库存),仅通过业务逻辑(如库存校验)和补偿机制处理冲突:
- 例如:两个订单同时预扣库存导致超卖,SAGA 会在支付阶段校验实际库存,失败的订单触发补偿释放库存。
- 这种设计避免了 AT/TCC 中 “锁长期持有导致的并发阻塞”,适合长事务的低阻塞需求。
四、长事务使用 SAGA 的好处
-
支持跨系统长流程长事务往往涉及多个独立系统(如订单、物流、财务),SAGA 通过状态机定义跨系统步骤,无需硬编码流程逻辑,适配复杂的跨系统协作。
-
容忍中间状态和人工干预长事务中常有人工操作(如审批、确认),SAGA 允许事务暂停等待人工操作,后续通过回调或定时任务继续执行,其他模式无法支持这种 “断点等待”。
-
低侵入性和高灵活性SAGA 通过配置文件(JSON/YAML)定义流程,新增步骤或修改补偿逻辑无需修改业务代码,适合长事务的需求迭代(如物流流程新增 “质检” 步骤)。
-
高容错性长事务执行时间长,发生故障的概率更高。SAGA 通过状态持久化和重试机制,确保故障后能恢复执行;通过补偿机制,确保最终数据一致。
结论
SAGA 模式看似与其他模式使用方式相似,但其无锁设计、状态持久化和补偿机制使其专为长事务设计:
- 长事务的核心需求是「允许长时间运行、支持断点续跑、容忍中间状态」,这些都是 AT/TCC 等短事务模式无法满足的。
- SAGA 放弃了即时一致性,通过最终一致性适配长事务场景,在跨系统、多步骤、长时间的业务中不可替代。
源码分析
Seata 的 SAGA 模式专为 长事务场景 设计(如跨多个微服务的订单流程、物流调度等),核心通过 状态机驱动 和 补偿机制 实现柔性事务,支持复杂流程编排和失败补偿。以下从源码层面解析其底层实现逻辑(基于 Seata 1.6.x 版本)。
一、SAGA 模式核心原理与角色
SAGA 模式的核心是将长事务拆分为多个 本地事务步骤,每个步骤对应一个 正向操作 和一个 补偿操作(用于失败时回滚)。Seata 中 SAGA 模式的核心角色:
- StateMachineEngine:状态机引擎,负责解析状态机定义、驱动流程执行、管理事务状态。
- SagaCoordinator:协调器,负责记录事务执行状态、触发补偿操作。
- SagaRepository:事务状态仓库,持久化事务实例和步骤状态(支持数据库、文件等存储)。
核心流程:
- 正常执行:按状态机定义的顺序执行正向操作,记录每个步骤的执行状态。
- 失败补偿:若某步骤执行失败,按 逆序 执行已完成步骤的补偿操作,最终达到事务一致性。
二、源码解析:SAGA 状态机定义与初始化
SAGA 模式通过 JSON/YAML 配置文件 定义事务流程(步骤、正向 / 补偿方法、依赖关系等),状态机引擎在启动时解析配置并初始化。
1. 状态机配置示例(JSON)
json
{
"name": "orderSaga",
"comment": "订单创建-支付-发货的长事务流程",
"startState": "createOrder",
"states": [
{
"name": "createOrder",
"type": "ServiceTask",
"action": {
"serviceName": "orderService",
"methodName": "createOrder",
"compensateMethod": "cancelOrder" // 补偿方法
},
"transition": "pay" // 下一步骤
},
{
"name": "pay",
"type": "ServiceTask",
"action": {
"serviceName": "paymentService",
"methodName": "pay",
"compensateMethod": "refund"
},
"transition": "deliver"
},
{
"name": "deliver",
"type": "ServiceTask",
"action": {
"serviceName": "deliveryService",
"methodName": "deliver",
"compensateMethod": "cancelDelivery"
},
"end": true // 流程终点
}
]
}
2. 状态机解析与引擎初始化
状态机引擎(StateMachineEngine)启动时加载配置文件,解析为可执行的状态机实例:
关键代码:StateMachineConfigParser(配置解析)
java
运行
public class StateMachineConfigParser {
public StateMachine parse(String configContent) {
// 1. 解析 JSON 配置为 StateMachine 实体
StateMachine stateMachine = JSON.parseObject(configContent, StateMachine.class);
// 2. 初始化每个状态(步骤)的 action 信息(正向/补偿方法)
for (State state : stateMachine.getStates()) {
if (state.getType() == StateType.ServiceTask) {
ServiceTaskState serviceTask = (ServiceTaskState) state;
Action action = serviceTask.getAction();
// 反射获取正向方法和补偿方法的元数据(参数、返回值等)
MethodInvoker invoke = buildMethodInvoker(
action.getServiceName(),
action.getMethodName()
);
MethodInvoker compensateInvoke = buildMethodInvoker(
action.getServiceName(),
action.getCompensateMethod()
);
serviceTask.setActionInvoker(invoke);
serviceTask.setCompensateInvoker(compensateInvoke);
}
}
return stateMachine;
}
// 构建方法调用器(通过 Spring 容器获取 bean 并反射方法)
private MethodInvoker buildMethodInvoker(String serviceName, String methodName) {
Object serviceBean = SpringContextHolder.getBean(serviceName);
Method method = findMethod(serviceBean.getClass(), methodName);
return new ReflectiveMethodInvoker(serviceBean, method);
}
}
关键代码:StateMachineEngineImpl(引擎初始化)
java
运行
public class StateMachineEngineImpl implements StateMachineEngine {

最低0.47元/天 解锁文章
4696

被折叠的 条评论
为什么被折叠?



