























在 Go 语言中使用 Seata 实现 Saga 模式,核心在于使用 seata-go 框架。
与 Java 版本通常使用 JSON/XML 状态机配置不同,Go 版本的 Saga 更倾向于代码编排(Code-based Orchestration),利用 Go 语言的结构体和接口特性来定义事务流程。
以下是基于 seata-go 实现 Saga 模式的完整指南。
首先,你需要引入 seata-go 的依赖:
go get github.com/apache/seata-go
同时,确保你已经部署了 Seata Server (TC),并且在 Go 项目的配置文件中(通常是 conf/seatago.yml 或代码配置)正确连接到了 TC 地址。
在 Saga 模式中,每个步骤都是一个“参与者”。你需要定义 Go 结构体来实现具体的业务逻辑(正向操作)和补偿逻辑。
假设我们有一个 订单创建 和 库存扣减 的流程。
package service
import (
"fmt"
"github.com/apache/seata-go/pkg/saga/engine"
)
// 1. 定义订单服务参与者
type OrderService struct {}
// 正向操作:创建订单
func (o *OrderService) CreateOrder(orderID string) error {
fmt.Printf("🛒 [Order] 创建订单: %s\n", orderID)
// 模拟业务逻辑
return nil
}
// 补偿操作:取消订单
func (o *OrderService) CancelOrder(orderID string) error {
fmt.Printf("🚫 [Order] 取消订单: %s\n", orderID)
// 模拟回滚逻辑
return nil
}
// 2. 定义库存服务参与者
type InventoryService struct {}
// 正向操作:扣减库存
func (i *InventoryService) DeductStock(productID string, count int) error {
fmt.Printf("📦 [Inventory] 扣减库存: %s, 数量: %d\n", productID, count)
// 模拟扣减
if productID == "BAD_PRODUCT" {
return fmt.Errorf("库存不足") // 模拟异常
}
return nil
}
// 补偿操作:恢复库存
func (i *InventoryService) RestoreStock(productID string, count int) error {
fmt.Printf("↩️ [Inventory] 恢复库存: %s, 数量: %d\n", productID, count)
// 模拟恢复
return nil
}
这是 Seata Go 版本的核心。你需要使用 engine 包来构建状态机,定义步骤的顺序、参数传递以及补偿关系。
package main
import (
"context"
"log"
"your_project/service" // 引入上面的服务包
"github.com/apache/seata-go/pkg/saga/engine"
"github.com/apache/seata-go/pkg/saga/statemachine"
)
func main() {
// 初始化服务实例
orderSvc := &service.OrderService{}
inventorySvc := &service.InventoryService{}
// 1. 创建状态机定义
// 在实际生产中,建议将状态机定义持久化到数据库,这里为了演示直接在代码中构建
stateMachine := &statemachine.StateMachine{
Name: "CreateOrderSaga",
TenantId: "default",
}
// 2. 定义步骤 1: 创建订单
// 使用 AddServiceTask 添加服务任务
stateMachine.AddServiceTask("createOrder",
orderSvc.CreateOrder, // 正向方法
orderSvc.CancelOrder, // 补偿方法
)
// 3. 定义步骤 2: 扣减库存
stateMachine.AddServiceTask("deductStock",
inventorySvc.DeductStock, // 正向方法
inventorySvc.RestoreStock, // 补偿方法
)
// 4. 定义执行顺序
// 先执行 createOrder,成功后执行 deductStock
stateMachine.AddTransition("createOrder", "deductStock")
// 定义结束状态
stateMachine.AddEndState("deductStock")
// 5. 启动引擎并执行
// 注意:这里需要 Seata-go 的引擎初始化配置,此处省略配置加载代码
// engine.Init()
// 准备业务参数
params := map[string]interface{}{
"orderID": "ORD_123456",
"productID": "PROD_888",
"count": 10,
}
// 启动 Saga
// context 用于传递全局事务 ID (XID) 等信息
ctx := context.Background()
log.Println("🚀 开始执行 Saga 事务...")
// 调用启动
// 注意:实际 API 可能会随版本更新,请以最新版 seata-go 文档为准
// 这里演示逻辑流程
err := engine.Execute(ctx, stateMachine, params)
if err != nil {
log.Printf("❌ Saga 执行失败: %v", err)
// Seata-go 会自动根据状态机定义,反向调用 CancelOrder 或 RestoreStock
} else {
log.Println("✅ Saga 事务执行成功!")
}
}
在生产环境中,为了防止服务宕机导致事务状态丢失,Seata 的 Saga 状态机定义(JSON 或 对象结构)和执行状态通常存储在数据库中。
seata-go 提供了 StateLogStore 接口,你可以实现该接口将状态存入 MySQL 或 Redis。Saga 的精髓在于上下文传递。
orderID),需要作为参数传递给下一步(DeductStock)。seata-go 中,这通常通过 Context 或者 Map 在步骤间共享。DeductStock 返回 error 时,引擎会捕获该异常。RestoreStock,再调用 CancelOrder)。既然你在 Go 生态中,不得不提 DTM。虽然 Seata 是阿里出品,但在 Go 语言中,DTM 对 Saga 模式的支持往往被认为更“Go 风格”。
| 特性 | Seata-go Saga | DTM (Go) |
|---|---|---|
| 编排方式 | 偏向结构化配置/状态机定义 | 纯代码流式编排 (saga.Add(...)) |
| 学习曲线 | 较高(需理解 Seata 的状态机概念) | 低(API 非常直观) |
| 生态背景 | 适合 Java/Go 混合架构,统一使用 Seata | 适合纯 Go 架构,或微服务架构较新的团队 |
| 代码风格 | 定义 StateMachine 对象 |
链式调用,类似 saga.Add(url, compensateUrl, data) |
如果你发现 Seata-go 的配置过于繁琐,或者文档不够直观,强烈建议尝试 DTM 的 Saga 模式,它可能是目前 Go 语言中体验最好的分布式事务实现。
在 Go 中使用 Seata Saga:
seata-go 包。statemachine 包构建状态机,定义步骤和顺序。engine.Execute 启动事务。此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。