【架构实战】分布式事务解决方案

一、分布式事务的挑战

在微服务架构下,一个业务操作可能涉及多个服务的数据修改。传统的本地事务无法保证跨服务的数据一致性。

经典场景:

复制代码
用户下单 → 订单服务扣库存 → 支付服务扣余额 → 物流服务创建运单

任何一步失败,都需要回滚之前的操作

二、CAP定理回顾

  • C(一致性):所有节点数据一致
  • A(可用性):每个请求都能得到响应
  • P(分区容错):网络分区时系统仍能工作

三者只能满足其二,分布式系统必须选择CP或AP。

三、主流解决方案

方案1:2PC(两阶段提交)

复制代码
阶段1:Prepare(准备)
  协调者 → 所有参与者:准备提交?
  参与者 → 协调者:准备就绪 ✓/✗

阶段2:Commit/Rollback(提交/回滚)
  全部就绪 → Commit
  任一失败 → Rollback

优点 :强一致性
缺点:同步阻塞,性能差,单点故障

方案2:TCC(Try-Confirm-Cancel)

java 复制代码
// Try:预留资源
public boolean tryDeduct(String userId, BigDecimal amount) {
    Account account = accountMapper.selectById(userId);
    if (account.getFrozen().add(amount).compareTo(account.getBalance()) > 0) {
        return false;
    }
    accountMapper.freeze(userId, amount);
    return true;
}

// Confirm:确认提交
public void confirmDeduct(String userId, BigDecimal amount) {
    accountMapper.deduct(userId, amount);
}

// Cancel:取消回滚
public void cancelDeduct(String userId, BigDecimal amount) {
    accountMapper.unfreeze(userId, amount);
}

优点 :性能好,无锁
缺点:业务侵入性强,需实现三个接口

方案3:Saga模式

复制代码
T1 → T2 → T3 → T4
↓    ↓    ↓    ↓
C1 ← C2 ← C3 ← C4  (补偿操作)

正向操作链 + 补偿操作链
java 复制代码
// Saga编排器
public class OrderSaga {
    
    public void execute(Order order) {
        try {
            orderService.create(order);
            inventoryService.deduct(order);
            paymentService.pay(order);
            shippingService.create(order);
        } catch (Exception e) {
            // 按相反顺序补偿
            shippingService.cancel(order);
            paymentService.refund(order);
            inventoryService.restore(order);
            orderService.cancel(order);
        }
    }
}

方案4:可靠消息最终一致性

java 复制代码
// 本地消息表
@Transactional
public void createOrder(Order order) {
    orderMapper.insert(order);
    
    // 同一事务中写入本地消息表
    localMessageMapper.insert(new LocalMessage(
        order.getId(), "ORDER_CREATED", order.toString()
    ));
}

// 定时任务扫描消息表,投递到MQ
@Scheduled(fixedRate = 5000)
public void scanAndSend() {
    List messages = localMessageMapper
        .selectUnsentList();
    for (LocalMessage msg : messages) {
        try {
            mqTemplate.send(msg.getTopic(), msg.getContent());
            msg.setStatus("SENT");
            localMessageMapper.updateById(msg);
        } catch (Exception e) {
            log.error("消息投递失败", e);
        }
    }
}

四、Seata框架实战

yaml 复制代码
# Seata Server配置
seata:
  enabled: true
  application-id: order-service
  tx-service-group: my_tx_group
  service:
    vgroup-mapping:
      my_tx_group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
java 复制代码
// 使用@GlobalTransactional注解
@Service
public class OrderService {
    
    @Autowired
    private InventoryClient inventoryClient;
    
    @Autowired
    private PaymentClient paymentClient;
    
    @GlobalTransactional(name = "create-order", timeoutMills = 30000)
    public Order createOrder(OrderRequest request) {
        // 1. 创建订单
        Order order = orderMapper.insert(request);
        
        // 2. 扣减库存(远程调用)
        inventoryClient.deduct(request.getProductId(), request.getQuantity());
        
        // 3. 创建支付单(远程调用)
        paymentClient.create(order.getId(), request.getAmount());
        
        return order;
    }
}

五、方案对比与选型

方案 一致性 性能 复杂度 适用场景
2PC 强一致 传统数据库
TCC 最终一致 资金类业务
Saga 最终一致 长流程业务
可靠消息 最终一致 异步场景

选型建议

  • 强一致性要求:TCC
  • 最终一致性可接受:Saga 或 可靠消息
  • 简单场景:本地消息表
  • 对性能要求高:Saga

六、常见问题

Q1:空回滚怎么办?

A:记录事务状态,执行Cancel前检查是否已执行Try

Q2:悬挂问题?

A:通过全局事务ID关联,保证幂等性

Q3:补偿操作也失败了?

A:引入重试机制 + 人工干预兜底

七、总结

分布式事务没有银弹,需要根据业务特点选择合适方案:

  • 核心原则:BASE理论(基本可用、软状态、最终一致)
  • 设计思路:宁可补偿,不可阻塞
  • 工程实践:幂等性是基础,重试是保障

思考题:你的项目中如何处理分布式事务?有没有遇到过数据不一致的问题?


个人观点,仅供参考

相关推荐
Test-Sunny2 小时前
【实战问题汇总】大模型ai测试
ai·架构
2401_840192272 小时前
监控的作用
分布式·kubernetes
hf2000122 小时前
零成本迁移,原地加速,成本降低60%:火花思维基于云器Lakehouse升级实践
大数据·分布式·spark·lakehouse
Allen_LVyingbo2 小时前
自进化医疗智能体:动态记忆与持续运行的Python架构编程(上)
数据结构·python·架构·动态规划·健康医疗
国科安芯2 小时前
商业航天视角下角度编码传感器的应用与MCU的集成适配
大数据·网络·单片机·嵌入式硬件·架构·制造·安全性测试
毛骗导演2 小时前
Agent 工具生态深度对比:OpenClaw vs LangChain vs CrewAI 的 tool calling 设计哲学
前端·架构
敲代码的约德尔人2 小时前
前端架构师成长之路:彻底搞懂 RSC,从“零 Bundle”原理到四大深水区避坑指南
前端·架构
chaofan9802 小时前
拒绝单体模型依赖:从 GPT-5.4 与 Claude 生产力之争看分布式 AI 网关的必要性
人工智能·分布式·gpt
x2lab3 小时前
软考架构-软件工程【考什么,怎么考】
架构·软件工程·软考