分布式事务是 RPC 调用中的难点问题,涉及多个服务之间的数据一致性保证:
问题背景: 在微服务架构中,一个业务操作可能涉及多个服务的调用,如何保证这些服务之间的数据一致性是一个挑战。
分布式事务理论:
1. CAP 定理
- 一致性(Consistency):所有节点同时看到相同的数据
- 可用性(Availability):每个请求都能得到响应
- 分区容错性(Partition Tolerance):系统在网络分区时仍能继续运行
- 结论:在分布式系统中,只能同时满足两个特性
2. BASE 理论
- 基本可用(Basically Available):系统保证基本可用
- 软状态(Soft State):允许数据存在中间状态
- 最终一致性(Eventually Consistent):经过一段时间后数据最终一致
常见解决方案:
1. 两阶段提交(2PC)
- 准备阶段:协调者询问所有参与者是否可以提交
- 提交阶段:根据参与者反馈决定提交或回滚
- 优点:强一致性
- 缺点:性能差,存在单点故障,阻塞
- 适用场景:对一致性要求极高的场景
2. 三阶段提交(3PC)
- 在 2PC 基础上增加预提交阶段
- 减少阻塞时间
- 仍然存在性能问题
3. TCC(Try-Confirm-Cancel)
- Try 阶段:预留资源,检查业务规则
- Confirm 阶段:确认执行业务操作
- Cancel 阶段:取消操作,释放资源
- 优点:性能较好,最终一致性
- 缺点:代码侵入性强,需要实现三个接口
- 实现示例:
java
public interface OrderService { // Try:创建订单,预扣库存 @Compensable boolean createOrder(Order order); // Confirm:确认订单 void confirmOrder(Long orderId); // Cancel:取消订单,回滚库存 void cancelOrder(Long orderId); }
4. 本地消息表
- 在本地数据库中记录消息
- 定时任务扫描消息表并发送
- 消息消费成功后删除记录
- 优点:实现简单,可靠性高
- 缺点:需要额外的存储和定时任务
- 适用场景:异步场景,最终一致性
5. 事务消息(如 RocketMQ)
- 发送半消息
- 执行本地事务
- 提交或回滚消息
- 消费者消费消息
- 优点:性能好,支持高并发
- 缺点:依赖消息中间件
- 适用场景:高并发场景,最终一致性
6. Saga 模式
- 将长事务拆分为多个本地事务
- 每个本地事务都有对应的补偿操作
- 按顺序执行,失败时执行补偿
- 优点:性能好,适合长事务
- 缺点:需要设计补偿逻辑,可能产生脏读
- 适用场景:长事务,业务流程复杂
7. Seata(阿里开源)
- 支持 AT、TCC、SAGA、XA 模式
- AT 模式:
- 一阶段:解析 SQL,记录前镜像和后镜像
- 二阶段:提交或回滚,通过镜像数据恢复
- 优点:对业务代码侵入小
- 缺点:需要数据库支持
- 适用场景:Java 生态,Spring Cloud 微服务
实现示例(Seata AT 模式):
java@GlobalTransactional(name = "create-order", rollbackFor = Exception.class) public void createOrder(Order order) { // 扣减库存 inventoryService.deductStock(order.getProductId(), order.getQuantity()); // 创建订单 orderMapper.insert(order); // 扣减余额 accountService.deductBalance(order.getUserId(), order.getAmount()); }
选择建议:
- 强一致性要求:2PC、3PC、Seata XA
- 高并发场景:TCC、事务消息、Seata AT
- 长事务:Saga 模式
- 简单场景:本地消息表
- Java 生态:Seata 框架
- 最终一致性可接受:TCC、Saga、事务消息
注意事项:
- 根据业务场景选择合适的方案
- 考虑性能和一致性的平衡
- 做好幂等性设计
- 完善的监控和告警机制
- 定期进行故障演练