Files
interview/questions/01-分布式系统/分布式事务.md
yasinshaw 0e46a367c4 refactor: rename files to Chinese and organize by category
Organized 50 interview questions into 12 categories:
- 01-分布式系统 (9 files): 分布式事务, 分布式锁, 一致性哈希, CAP理论, etc.
- 02-数据库 (2 files): MySQL索引优化, MyBatis核心原理
- 03-缓存 (5 files): Redis数据结构, 缓存问题, LRU算法, etc.
- 04-消息队列 (1 file): RocketMQ/Kafka
- 05-并发编程 (4 files): 线程池, 设计模式, 限流策略, etc.
- 06-JVM (1 file): JVM和垃圾回收
- 07-系统设计 (8 files): 秒杀系统, 短链接, IM, Feed流, etc.
- 08-算法与数据结构 (4 files): B+树, 红黑树, 跳表, 时间轮
- 09-网络与安全 (3 files): TCP/IP, 加密安全, 性能优化
- 10-中间件 (4 files): Spring Boot, Nacos, Dubbo, Nginx
- 11-运维 (4 files): Kubernetes, CI/CD, Docker, 可观测性
- 12-面试技巧 (1 file): 面试技巧和职业规划

All files renamed to Chinese for better accessibility and
organized into categorized folders for easier navigation.

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-01 00:10:53 +08:00

7.7 KiB
Raw Blame History

分布式事务

问题

背景:在微服务架构中,我们经常遇到跨服务的数据一致性问题。

问题

  1. 请描述分布式事务的常见解决方案(至少 3 种)
  2. 它们的优缺点和适用场景是什么?
  3. 你在实际项目中是如何选择的?有没有遇到过什么坑?

标准答案

1. 常见解决方案

方案一2PC (Two-Phase Commit两阶段提交)

原理

  • 准备阶段:协调者询问所有参与者是否可以提交
  • 提交阶段:如果所有参与者都回复"可以",则发送提交指令;否则发送回滚指令

优点

  • 强一致性
  • 原理简单,易于理解

缺点

  • 同步阻塞:所有参与者在事务提交前都处于阻塞状态
  • 单点故障:协调者故障会导致参与者一直阻塞
  • 数据不一致:在第二阶段,部分节点收到提交指令,部分未收到

适用场景

  • 传统关系型数据库XA 协议)
  • 对一致性要求极高,可接受性能损耗的场景

实际应用

  • MySQL XA 事务
  • Java JTA (Java Transaction API)

方案二3PC (Three-Phase Commit三阶段提交)

原理 在 2PC 基础上增加 CanCommit 阶段:

  1. CanCommit协调者询问参与者是否可以执行
  2. PreCommit参与者预执行并回复
  3. DoCommit正式提交

优点

  • 相比 2PC 减少了阻塞时间
  • 引入超时机制,参与者可以自动决策

缺点

  • 仍然存在数据不一致风险
  • 协议更复杂,实现成本高
  • 性能提升有限

适用场景

  • 很少在实际生产中使用,更多是理论意义

方案三TCC (Try-Confirm-Cancel补偿事务)

原理

  • Try 阶段:尝试执行业务,完成资源的检查和预留
  • Confirm 阶段:确认执行业务,使用 Try 阶段预留的资源
  • Cancel 阶段:取消执行业务,释放 Try 阶段预留的资源

代码示例

// Try 阶段
public boolean try() {
    // 检查账户余额
    // 冻结相应金额(预留资源)
    // return true/false
}

// Confirm 阶段
public boolean confirm() {
    // 扣除冻结金额
    // 真正完成转账
}

// Cancel 阶段
public boolean cancel() {
    // 释放冻结金额
    // 恢复原始状态
}

优点

  • 最终一致性
  • 性能较好,相比 2PC 没有长时间锁资源
  • 业务可控性强

缺点

  • 代码侵入性强:每个业务都需要写三个接口
  • 开发成本高:需要考虑各种异常情况
  • 容易遗漏Cancel 接口如果实现不完整会导致资源泄露

适用场景

  • 对性能有一定要求
  • 业务逻辑清晰,可以拆分成 Try/Confirm/Cancel
  • 高并发场景

实际应用

  • 阿里巴巴 Seata 的 TCC 模式
  • 支付系统、订单系统

方案四:本地消息表(异步确保)

原理

  1. 上游服务在同一本地事务中:
    • 完成业务操作
    • 存储一条消息到本地消息表(状态为"待发送"
  2. 定时任务扫描消息表,发送消息到 MQ
  3. 下游服务消费 MQ执行业务逻辑
  4. 下游服务成功后通知上游更新消息状态

优点

  • 实现简单
  • 可靠性高(消息持久化)
  • 支持重试

缺点

  • 需要维护本地消息表
  • 定时任务有延迟
  • 需要处理消息重复消费(幂等性)

适用场景

  • 可以接受最终一致性
  • 对实时性要求不高
  • 高并发场景

实际应用

  • 支付宝到账通知
  • 订单创建后的物流通知

方案五MQ 事务消息RocketMQ 方案)

原理

  1. 发送半消息Half Message到 MQ消息对消费者不可见
  2. 执行本地事务
  3. 提交/回滚消息:
    • 本地事务成功 → 提交消息(消息对消费者可见)
    • 本地事务失败 → 删除消息
  4. MQ 提供反查机制:如果长时间未收到确认,主动查询业务方事务状态

优点

  • 解耦性强
  • 性能好
  • 支持大规模分布式事务

缺点

  • 依赖特定 MQ如 RocketMQ
  • 需要实现反查接口
  • 消息可能有延迟

适用场景

  • 高并发、大规模分布式系统
  • 可以接受最终一致性
  • 需要解耦上下游服务

实际应用

  • RocketMQ 事务消息
  • 双11 大促场景

方案六Saga 模式

原理 将长事务拆分为多个本地短事务,每个短事务都有对应的补偿操作:

  • 正向操作T1, T2, T3, ..., Tn
  • 补偿操作Cn, ..., C3, C2, C1反向补偿

示例

预订行程 Saga
1. 预订航班 (T1)
2. 预订酒店 (T2)
3. 预订租车 (T3)

如果 T2 失败:
1. 取消航班 (C1)
2. 返回失败给用户

优点

  • 适合长事务、业务流程复杂的场景
  • 最终一致性
  • 可以跨多个服务

缺点

  • 需要为每个操作设计补偿逻辑
  • 补偿操作可能失败,需要处理
  • 无法保证隔离性(脏读问题)

适用场景

  • 业务流程长、涉及多个服务
  • 旅行预订、电商下单
  • 微服务编排

实际应用

  • Apache ServiceComb Saga
  • Netflix Conductor

2. 方案对比总结

方案 一致性 性能 复杂度 适用场景
2PC 强一致性 低(同步阻塞) 传统数据库
3PC 强一致性 很少使用
TCC 最终一致性 高(业务侵入) 高并发、强业务控制
本地消息表 最终一致性 高可靠性、可接受延迟
MQ 事务消息 最终一致性 大规模、高并发、解耦
Saga 最终一致性 高(补偿逻辑) 长事务、业务编排

3. 实际项目选择建议

选择决策树

是否需要强一致性?
├─ 是 → 2PCXA 事务)
└─ 否 → 最终一致性
    │
    ├─ 业务可以拆分为 Try/Confirm/Cancel
    │   ├─ 是 → TCC高并发、强控制
    │   └─ 否 → 继续判断
    │
    ├─ 使用 RocketMQ
    │   ├─ 是 → MQ 事务消息
    │   └─ 否 → 继续判断
    │
    ├─ 业务流程长、涉及多服务?
    │   ├─ 是 → Saga
    │   └─ 否 → 本地消息表

常见坑和注意事项

  1. 幂等性问题(所有方案都需要考虑)

    • 重复请求导致的重复扣款、重复发货
    • 解决:使用唯一业务 ID、Redis 分布式锁
  2. 空补偿问题TCC

    // Cancel 被调用时Try 可能还没执行
    public void cancel() {
        // 需要检查是否有冻结记录
        if (没有冻结记录) {
            return; // 空补偿,直接返回
        }
        // 执行取消逻辑
    }
    
  3. 悬挂问题TCC

    • Confirm 比 Cancel 先到
    • 解决:记录事务状态,拒绝后续操作
  4. 消息丢失MQ 方案)

    • 网络抖动导致消息丢失
    • 解决ACK 机制 + 重试 + 死信队列
  5. 资源锁定时间2PC

    • 长时间锁资源导致性能下降
    • 解决:控制事务规模,拆分大事务

4. 阿里 P7 加分项

实际项目经验

  • 设计并实现过千万级用户的分布式事务系统
  • 处理过分布式事务的性能瓶颈(如连接池优化、并发度控制)
  • 有 TCC/Saga 的踩坑经验和解决方案

深度理解

  • 理解 CAP 理论在实际场景中的权衡
  • 能根据业务特点选择合适的一致性级别
  • 有监控和告警体系,能快速定位分布式事务问题

架构能力

  • 能设计支持多种分布式事务模式的统一框架
  • 考虑降级和熔断策略
  • 有混沌工程实践(注入故障测试系统恢复能力)