当 A、B、C、D 四个微服务都涉及更新或插入 (写操作)时,由于每个服务有自己的独立数据库,传统的单机事务无法覆盖多个数据库,因此必须采用分布式事务方案来保证数据一致性。
下面我按常见的分布式事务模式来分析,并给出适用场景与示例。
1. 问题分析
- 场景:一次业务请求需要依次或并行调用 A、B、C、D 四个服务,每个服务在自己的数据库中做增删改操作。
- 目标 :保证这四个操作要么全部成功 ,要么全部失败(原子性),并且在发生故障时能正确恢复或补偿。
- 挑战:网络不可靠、服务可能宕机、部分成功部分失败会导致数据不一致。
2. 分布式事务解决方案
2.1 两阶段提交(2PC, Two-Phase Commit)
-
原理 :
- 准备阶段:事务协调者询问所有参与者(A、B、C、D)是否可以提交,参与者锁定资源并返回"就绪"。
- 提交阶段:如果所有参与者都就绪,协调者发送提交命令;否则发送回滚命令。
-
优点:强一致性。
-
缺点 :
- 同步阻塞,性能差。
- 协调者单点故障风险。
- 在微服务+多数据库场景下实现复杂,现代应用较少使用(尤其互联网高并发场景)。
适用:传统企业级应用,对一致性要求极高,并发量不大。
2.2 三阶段提交(3PC)
- 在 2PC 基础上引入超时机制和预提交阶段,减少阻塞范围,但依然有协调者单点问题和复杂度,实际很少用。
2.3 Saga 模式
-
原理:将一个长事务拆分为多个本地短事务,每个本地事务完成后发布事件触发下一个本地事务;如果某个本地事务失败,则按相反顺序执行补偿事务(Compensating Transaction)来撤销之前的操作。
-
两种实现方式:
- 编排式(Orchestration):由一个中心协调器(Saga Orchestrator)按顺序调用各服务的本地事务/补偿操作。
- 协同式(Choreography):每个服务监听事件,自己决定下一步动作,无中心协调器。
-
优点:
- 避免全局锁,性能好,适合微服务。
- 最终一致性。
-
缺点:
- 不保证隔离性(可能出现脏写)。
- 补偿逻辑复杂,有时难以实现(例如物理删除难以补偿)。
-
适用:高并发互联网微服务,可接受最终一致性。
示例(编排式 Saga) :
业务:创建订单 → 扣库存 → 扣余额 → 记录物流
- 步骤 1:订单服务创建订单(本地事务)
- 步骤 2:库存服务扣库存(本地事务)
- 步骤 3:账户服务扣余额(本地事务)
- 步骤 4:物流服务生成运单(本地事务)
若步骤 3 失败,则依次执行: - 补偿步骤 2:库存服务恢复库存
- 补偿步骤 1:订单服务取消订单
2.4 TCC 模式(Try-Confirm-Cancel)
-
原理:将每个服务的方法分为三个阶段:
- Try:预留业务资源(如冻结库存、预扣金额)。
- Confirm:确认执行业务操作,使用 Try 阶段预留的资源。
- Cancel:取消操作,释放 Try 阶段预留的资源。
-
优点:
- 比 Saga 更可控,可实现类似强一致的效果(通过预留资源)。
- 避免长期资源锁定。
-
缺点:
- 每个业务都要实现 Try/Confirm/Cancel 接口,开发复杂。
- 对业务侵入性强。
-
适用:核心金融业务(支付、交易),对一致性要求高且资源可预留。
示例 :
订单服务:
- Try:检查并锁定订单状态为"处理中"
- Confirm:更新为"已确认"
- Cancel:更新为"已取消"
库存服务: - Try:冻结相应库存
- Confirm:扣减冻结库存
- Cancel:解冻库存
2.5 本地消息表(可靠事件模式)
-
原理:
- 业务执行时,将事件写入本地数据库的消息表(与业务操作在同一事务中)。
- 后台任务轮询消息表,将未发送的事件发送到消息队列。
- 消费者服务收到消息后执行本地事务,并确认消息。
- 如果消费失败,重试或进入死信队列人工处理。
-
优点:实现相对简单,避免分布式事务框架。
-
缺点:有数据不一致窗口,依赖消息队列可靠性。
-
适用:异步场景,允许短暂不一致。
2.6 最大努力通知
- 类似本地消息表,但不保证一定成功,通过多次重试尽可能达到最终一致,常用于外部系统交互(如支付回调)。
3. 方案选型建议
| 方案 | 一致性强度 | 性能 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| 2PC | 强一致 | 差 | 中 | 传统企业应用,低并发 |
| Saga | 最终一致 | 好 | 中 | 微服务主流,高并发 |
| TCC | 接近强一致 | 中 | 高 | 金融核心业务 |
| 本地消息表 | 最终一致 | 好 | 中低 | 异步、解耦场景 |
4. 实践建议
- 业务分析:先判断能否将操作合并到更少的服务(减少跨服务事务)。
- 降低一致性要求:很多业务可接受最终一致性,用 Saga 或消息表即可。
- 幂等设计:所有参与服务必须实现幂等,防止重复执行。
- 补偿/回滚设计:提前考虑如何撤销操作(逻辑删除、状态回滚、反向操作)。
- 监控与重试:完善的日志、监控、告警与重试机制。
- 测试:模拟各种失败场景(网络超时、服务宕机)验证一致性保障。
总结 :
当 A、B、C、D 都是写操作时,推荐使用 Saga 或 TCC 模式来保证数据一致性,具体选择取决于业务对一致性的要求、性能要求和开发维护成本。