分布式事务解决方案:最佳实践(零基础 Go 教程)
威武虎
2025-12-14 15:13
阅读 779
大家好,我是你们的老朋友,一个在大厂干了3年后端开发、业余在B站做技术分享的UP主。最近很多粉丝私信我:“分布式事务到底该怎么学?有没有适合小白的 Go 实战教程?”——这让我想起我当初学的时候,面对一堆“两阶段提交”、“Saga”、“TCC”术语时的迷茫。今天,我就用最通俗的语言,带你从零开始,亲手用 Go 写一个简单的分布式事务 demo!
本文目标:哪怕你只会
fmt.Println("Hello"),也能理解分布式事务的核心思想,并动手跑通代码。
一、什么是分布式事务?为什么需要它?
想象这样一个场景:
- 用户在前端下单买书(比如一本《Go语言实战》)
- 后端要同时做两件事:
- 扣减库存(调用库存服务)
- 创建订单(调用订单服务)
这两个操作分布在两个不同的服务(甚至不同数据库)中。如果扣库存成功了,但创建订单失败了,就会出现“库存少了但没生成订单”的问题——这就是典型的数据不一致。
分布式事务的目标就是:要么全部成功,要么全部失败,保证跨服务的数据一致性。
二、环境准备(5分钟搞定)
我们用 Go + SQLite(轻量,无需额外安装数据库)来模拟两个微服务。
所需工具
| 工具 | 版本 | 说明 |
|---|---|---|
| Go | ≥1.19 | 官网下载安装即可 |
| Git | 最新版 | 用于克隆示例代码(可选) |
初始化项目
mkdir distributed-tx-demo
cd distributed-tx-demo
go mod init demo
我们会创建两个“伪服务”:
order-service:处理订单stock-service:处理库存
三、核心概念:三种主流方案(小白也能懂)
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 2PC(两阶段提交) | 协调者先问“能不能提交”,都同意后再真正提交 | 强一致性 | 性能差、阻塞 | 银行转账等强一致场景 |
| TCC(Try-Confirm-Cancel) | 先冻结资源(Try),再确认(Confirm)或回滚(Cancel) | 灵活、性能好 | 业务侵入强 | 电商下单、支付 |
| Saga | 每个服务本地事务 + 补偿事务(失败时执行反向操作) | 易实现、高可用 | 最终一致性 | 订单超时取消等 |
我们选择 Saga 模式 来教学——代码简单,逻辑清晰,最适合新手入门!
四、实战:用 Go 实现一个 Saga 分布式事务
步骤 1:定义两个服务的数据结构
// stock.go
type StockService struct {
inventory map[string]int // 商品ID -> 库存数量
}
func NewStockService() *StockService {
return &StockService{
inventory: map[string]int{"book-001": 10},
}
}
// 扣库存(正向操作)
func (s *StockService) Deduct(productID string, qty int) error {
if s.inventory[productID] < qty {
return fmt.Errorf("库存不足")
}
s.inventory[productID] -= qty
fmt.Printf("✅ 库存已扣减: %s, 剩余: %d\n", productID, s.inventory[productID])
return nil
}
// 补偿:恢复库存(反向操作)
func (s *StockService) Restore(productID string, qty int) {
s.inventory[productID] += qty
fmt.Printf("🔄 库存已恢复: %s, 当前: %d\n", productID, s.inventory[productID])
}
// order.go
type OrderService struct {
orders map[string]bool // 订单ID -> 是否创建成功
}
func NewOrderService() *OrderService {
return &OrderService{orders: make(map[string]bool)}
}
// 创建订单(正向操作)
func (o *OrderService) Create(orderID string) error {
// 模拟网络超时导致失败
if rand.Intn(100) < 30 { // 30% 概率失败
return fmt.Errorf("创建订单失败(模拟异常)")
}
o.orders[orderID] = true
fmt.Printf("✅ 订单已创建: %s\n", orderID)
return nil
}
// 补偿:删除订单(实际中可能是标记为“已取消”)
func (o *OrderService) Cancel(orderID string) {
delete(o.orders, orderID)
fmt.Printf("🔄 订单已取消: %s\n", orderID)
}
步骤 2:实现 Saga 协调器(核心!)
// saga.go
type SagaStep struct {
Action func() error // 正向操作
Compensate func() // 补偿操作
}
func RunSaga(steps []SagaStep) error {
var executedSteps []SagaStep
// 正向执行
for _, step := range steps {
if err := step.Action(); err != nil {
fmt.Printf("❌ 步骤失败: %v\n", err)
// 执行补偿
for i := len(executedSteps) - 1; i >= 0; i-- {
executedSteps[i].Compensate()
}
return err
}
executedSteps = append(executedSteps, step)
}
return nil
}
步骤 3:组合业务流程
// main.go
func main() {
stockSvc := NewStockService()
orderSvc := NewOrderService()
productID := "book-001"
orderID := "order-123"
qty := 1
steps := []SagaStep{
{
Action: func() error {
return stockSvc.Deduct(productID, qty)
},
Compensate: func() {
stockSvc.Restore(productID, qty)
},
},
{
Action: func() error {
return orderSvc.Create(orderID)
},
Compensate: func() {
orderSvc.Cancel(orderID)
},
},
}
err := RunSaga(steps)
if err != nil {
fmt.Println("💥 整个事务失败,已回滚!")
} else {
fmt.Println("🎉 分布式事务成功完成!")
}
}
运行效果(文字版“流程图”)
开始
│
├─▶ 扣减库存 → 成功 → 记录补偿动作
│
├─▶ 创建订单 → 失败(30%概率)
│ │
│ └─▶ 触发补偿:恢复库存
│
└─▶ 输出:整个事务失败,已回滚!
五、新手常见问题解答
❓ Q1:Saga 是最终一致性,会不会有脏读?
会!比如库存已扣但订单还没建完时,其他用户看到库存变少但查不到订单。解决办法:加状态字段(如“预扣库存”),前端展示时过滤掉中间状态。
❓ Q2:补偿操作失败了怎么办?
这是 Saga 的难点!通常做法:
- 重试补偿(最多 N 次)
- 记录失败日志,人工介入
- 设计幂等补偿(多次执行结果一致)
❓ Q3:Go 里有现成的分布式事务框架吗?
有的!比如 DTM(国人开源,支持 Go),但建议先手写理解原理,再用框架。
六、学习建议 & 避坑指南
✅ 下一步怎么学?
- 深入 Saga:研究如何持久化 Saga 状态(防止进程崩溃丢失上下文)
- 对比 TCC:尝试用 TCC 模式重写本 demo(Try 阶段冻结库存)
- 集成真实数据库:把内存 map 换成 MySQL + GORM
- 引入消息队列:用 RabbitMQ/Kafka 实现异步 Saga
⚠️ 避坑提醒
- 不要过度设计:单体应用别硬上分布式事务!
- 幂等性必须做:网络超时可能重复请求,所有操作要支持“重复执行无副作用”
- 监控告警:补偿失败一定要报警,否则数据就“静默不一致”了
结语
分布式事务听起来高大上,但拆解后不过是“做事+兜底”的朴素思想。我当初就是靠手写这种 mini demo 才真正理解的。希望这篇教程能帮你迈出第一步!
记住:没有银弹方案,只有“合适”的方案。根据业务容忍度(强一致 vs 最终一致)、团队能力、性能要求来选型。
如果你觉得有帮助,欢迎去 B站 搜索我的频道「Go后端研究所」,我会持续更新更多实战教程!下期见~
标签:前端教程后端Go
为你推荐
暂无相关推荐

评论 0