5 张图带你了解分布式事务 Saga 模式中的状态机
5 张图带你了解分布式事务 Saga 模式中的状态机
状态机在分布式系统中扮演着重要角色,特别是在处理复杂事务流程时。本文将深入探讨Seata中Saga模式的状态机实现,从基本概念到具体应用,帮助读者理解这一强大工具的工作原理和使用方法。
1. 状态机简介
状态机是一个数学模型,用于抽象工作中的运行状态和流转规则,通过协调相关信号来完成预先设定的操作。其核心概念包括:
- 状态:状态机当前的状态标识
- 状态转移:定义状态之间的转移路由
- 动作(Action):状态转移需要的操作
- 事件:触发操作的信号或口令
状态机通常应用于状态类型多、分支流程复杂、需要经过多个步骤才能达到最终状态的场景。
2. Saga模式
Saga模式是分布式事务中处理长事务的一种解决方案,其理论基础源于Hector & Kenneth在1987年发表的论文。在Saga模式中,如果部分分支事务已提交成功,而其中一个分支事务提交失败,状态机将触发所有已提交成功的分支事务进行回滚。
关键点:分支事务的提交和回滚逻辑需要由业务代码实现。
3. Saga实现
Seata中Saga模式基于状态机实现,使用时需要先绘制状态图,定义服务调用流程,并为每个节点配备补偿节点。以电商场景为例,涉及订单、账户、库存三个分支事务:
分支事务 | 动作 | 状态 |
---|---|---|
订单服务 | 保存订单 | 保存成功/失败 |
账户服务 | 扣减金额 | 扣减成功/失败 |
库存服务 | 扣减库存 | 扣减成功/失败 |
若任一分支事务提交失败,其他已成功事务需进行反向补偿。Seata状态机通过定义Json配置文件来实现这一过程,主要包括以下状态类型:
- ServiceTask:对应分支事务的提交操作
- Choice:用于流程选择
- CompensationTrigger:触发补偿服务
- Succeed:成功状态
- Fail:失败状态
3.1 ServiceTask
以"保存订单"状态为例:
"SaveOrder": {
"Type": "ServiceTask",
"ServiceName": "orderSave",
"ServiceMethod": "saveOrder",
"CompensateState": "DeleteOrder",
"Next": "ChoiceAccountState",
"Input": [
"$.[businessKey]",
"$.[order]"
],
"Output": {
"SaveOrderResult": "$.#root"
},
"Status": {
"#root == true": "SU",
"#root == false": "FA",
"$Exception{java.lang.Throwable}": "UN"
},
"Catch": [
{
"Exceptions": [
"java.lang.Throwable"
],
"Next": "CompensationTrigger"
}
]
}
3.2 Choice
以"ChoiceAccountState"为例:
"ChoiceAccountState": {
"Type": "Choice",
"Choices": [
{
"Expression": "[SaveOrderResult] == true",
"Next": "ReduceAccount"
}
],
"Default": "Fail"
}
3.3 Fail
当发生异常时,会跳转到CompensationTrigger:
"CompensationTrigger": {
"Type": "CompensationTrigger",
"Next": "Fail"
}
完整Json配置文件如下:
{
"Name": "buyGoodsOnline",
"Comment": "buy a goods on line, add order, deduct account, deduct storage ",
"StartState": "SaveOrder",
"Version": "0.0.1",
"States": {
// 各个状态的详细配置
}
}
4. 状态机应用
电商案例中,三个分支服务分别定义了三个State,对应的ServiceMethod如下:
- SaveOrder#saveOrder
- ReduceAccount#decrease
- ReduceStorage#decrease
状态机启动时需要传入参数:
StateMachineEngine stateMachineEngine = (StateMachineEngine) ApplicationContextUtils.getApplicationContext().getBean("stateMachineEngine");
Map<String, Object> startParams = new HashMap<>(3);
String businessKey = String.valueOf(System.currentTimeMillis());
startParams.put("businessKey", businessKey);
// 其他参数设置
StateMachineInstance inst = stateMachineEngine.startWithBusinessKey("buyGoodsOnline", null, businessKey, startParams);
5. 状态机原理
状态机的工作流程如下:
- 启动全局事务
- 记录状态机参数到本地数据库
- 注册分支事务到Seata Server
- 执行各状态并记录状态,通过EventQueue传递路由消息
- 最终提交或回滚全局事务
6. 高可用性
Seata状态机内嵌在应用中,上下文和执行日志存储在本地数据库,因此是无状态的。当应用宕机时,Seata Server会将恢复请求发送到存活实例,从数据库中恢复状态机上下文和执行日志。
7. 总结
本文详细介绍了Seata中Saga模式的状态机实现,从基本概念到具体应用,再到原理分析,为分布式系统开发提供了有价值的参考。状态机的设计思路和实现方式,不仅适用于Seata,也为其他场景下的状态机设计提供了有益的借鉴。