一、分布式事务的概念
分布式事务是指跨越多个数据库或服务的事务操作,需要保证ACID特性(原子性、一致性、隔离性、持久性)在分布式环境下的实现。在微服务架构和分布式系统中,一个业务操作往往需要协调多个独立的数据源或服务,这时就需要分布式事务来确保数据的一致性。
二、核心特性挑战
在分布式环境中实现ACID面临特殊挑战:
-
原子性:所有参与者要么全部提交,要么全部回滚
-
一致性:分布式系统的全局数据一致性
-
隔离性:并发操作的隔离难度更大
-
持久性:各节点故障恢复的复杂性
三、常见实现方案
以下单为例,在分布式服务中,实现下单、扣库存、冻结优惠券这类操作的事务一致性,通常有以下几种主流方案:
1. 2PC(两阶段提交)
核心思想:引入协调者,分两阶段保证多个服务操作的原子性。
原理:
-
准备阶段:协调者询问所有参与者是否可以提交
-
提交阶段:根据准备阶段的反馈决定提交或回滚
缺点:
-
同步阻塞,性能较差
-
协调者单点故障风险
-
不适合高并发场景
java
// 伪代码示例
public class TwoPhaseCommit {
// 第一阶段:准备
boolean prepare = participant.prepare(transaction);
// 第二阶段:提交或回滚
if (allPrepared) {
participant.commit(transaction);
} else {
participant.rollback(transaction);
}
}
2. TCC(Try-Confirm-Cancel)
最常用方案:业务层面实现补偿机制。
原理:
-
Try:预留资源,完成业务检查
-
Confirm:确认执行业务,实际提交
-
Cancel:回滚Try阶段的预留
下单流程示例:
java
java
// 第一阶段:Try(预留资源)
1. Try下单:创建"待确认"订单
2. Try库存:冻结库存(非实际扣减)
3. Try优惠券:锁定优惠券
// 第二阶段:Confirm(确认提交)
if (所有Try成功) {
Confirm下单:更新订单为"已确认"
Confirm库存:实际扣减库存
Confirm优惠券:标记优惠券已使用
} else {
// Cancel(回滚)
Cancel下单:删除订单
Cancel库存:释放冻结库存
Cancel优惠券:解锁优惠券
}
优点:
-
性能较好,资源锁定时间短
-
无中心化协调者
-
适合高并发场景
缺点:
-
业务侵入性强,需要实现三阶段接口
-
需要考虑空回滚、幂等、防悬挂等问题
3. 本地消息表
核心思想:通过本地事务+异步消息保证最终一致性。
原理:
-
业务与消息耦合在同一本地事务
-
消息系统保证消息可靠投递
-
消费者实现幂等性
sql
sql
-- 订单服务本地数据库
BEGIN TRANSACTION;
-- 1. 创建订单(本地事务)
INSERT INTO orders(...);
-- 2. 插入待发送消息(同一事务)
INSERT INTO message_table(order_id, event_type, status);
COMMIT;
-- 异步轮询发送消息
-- 消费者处理:扣库存、冻结优惠券
优点:
-
简单,无侵入
-
保证最终一致性
缺点:
-
消息表可能成为瓶颈
-
延迟相对较高
4. Saga模式
核心思想:将长事务拆分为多个本地事务,通过补偿操作回滚。
原理:
-
将长事务拆分为多个本地事务
-
每个本地事务都有对应的补偿操作
-
通过事件驱动的方式协调

正常流程:
下单成功 → 扣库存 → 冻结优惠券
异常时补偿:
下单成功 → 扣库存失败 → 取消订单
↓
下单成功 → 扣库存成功 → 冻结优惠券失败 → 恢复库存 → 取消订单
实现方式:

-
编排式:中央协调器编排各个服务
-
协同式:每个服务触发下一个服务
java
// Saga协调器示例
public class OrderSaga {
public void createOrder(Order order) {
try {
inventoryService.reserve(order);
paymentService.process(order);
shipmentService.schedule(order);
} catch (Exception e) {
// 执行补偿
inventoryService.cancelReserve(order);
paymentService.refund(order);
}
}
}
5. 基于可靠消息服务
使用RocketMQ、Kafka等支持事务消息的中间件。

四、方案对比
| 方案 | 一致性 | 性能 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| 2PC | 强一致 | 低 | 中 | 传统数据库分布式 |
| TCC | 最终一致 | 高 | 高 | 金融、电商核心业务 |
| Saga | 最终一致 | 高 | 高 | 长流程业务 |
| 本地消息表 | 最终一致 | 中 | 中 | 异步通知场景 |
| 消息队列 | 最终一致 | 高 | 低 | 高并发最终一致 |
五、 实际架构示例
电商下单系统常见设计:
sql
yaml
方案组合:
1. 创建订单:本地事务
2. 扣减库存:TCC或预扣库存
3. 优惠券:预冻结+最终扣减
4. 支付:通过支付回调保证最终一致性
补偿机制:
- 订单超时未支付:库存回退、优惠券释放
- 异常处理:重试、告警、人工介入
七、 选型建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 并发高、业务复杂 | TCC | 性能好,可控性强 |
| 简单业务、允许延迟 | 本地消息表 | 实现简单 |
| 跨系统、长流程 | Saga | 适合流程编排 |
| 强依赖消息队列 | 可靠消息 | 利用MQ能力 |
八、 最佳实践
-
尽量缩小分布式事务范围:能本地事务就不用分布式事务
-
最终一致性优先:大部分业务可接受最终一致性
-
做好补偿和重试:实现幂等性,防止重复处理
-
监控和告警:关键事务状态监控,失败及时告警
-
兜底方案:人工对账和修复流程
分布式事务没有银弹方案,需要根据具体业务场景、一致性要求和系统复杂度进行选择和设计。在实际应用中,通常采用多种方案组合的方式来满足不同的业务需求。
实际案例 :阿里、京东等电商平台通常采用 TCC + 消息队列 + 定时对账 的组合方案,在保证一致性的同时兼顾系统性能。