分布式事务八股文
分布式事务八股文
分布式事务的实现方式主要有以下几种:
1. 两阶段提交(2PC, Two-Phase Commit)
原理:
- 第一阶段(准备阶段,Prepare Phase):协调者向所有参与者发送事务准备请求,参与者执行事务并准备提交,但不真正提交,直到收到协调者的指令。
- 第二阶段(提交阶段,Commit Phase):如果所有参与者都准备成功,协调者发送提交请求;否则,发送回滚请求。
优点: - 确保事务的强一致性(ACID)。
缺点: - 存在同步阻塞问题,参与者在等待协调者的指令时无法释放资源。行锁、表锁
- 单点故障:如果协调者崩溃,可能导致事务无法完成。
- 数据不一致风险:如果协调者在第二阶段崩溃,可能导致部分提交,部分回滚。或者网络问题。
- 如果给第一个参与者发送提交之后,给第二个发送提交信号的时候崩溃,那就会出现不一致,而且网络分区也是一个问题,一个通一个不通,咋搞。这个无法解决。
> 这个两阶段提交,跟 Mysql redolog 和 binlog 这个两阶段提交完全不是一个东西(MySQL-基础概念篇-1-日志)。注意区分 |
---|
2. 三阶段提交(3PC, Three-Phase Commit)
原理:
- CanCommit 阶段:协调者询问所有参与者是否可以执行事务。
- PreCommit 阶段:如果所有参与者都同意,协调者发送预提交请求,并进入等待。
- DoCommit 阶段:协调者发送最终提交指令,参与者提交数据。
改进点: - 引入超时机制,减少阻塞问题。
- 参与者在等待提交时仍然可对外提供服务,提高可用性。
缺点: - 依然不能完全避免网络分区问题,可能导致数据不一致。
3. 本地消息表(异步保证最终一致性)
原理:
- 在本地事务中先将操作写入消息表。
- 事务提交后,独立的消息消费服务读取消息表并执行跨系统的事务操作。
- 如果执行失败,则通过重试机制保证最终一致性。
优点: - 高效、减少锁竞争。
- 可靠性高,可以避免分布式事务带来的问题。
缺点: - 需要额外的存储(消息表)。
- 需要处理消息重复消费的问题。
这种方式说白了就是 A 的事务先提交,然后 rpc 到 B 进行不停地重试,这个很基础很原始,不推荐使用。
4. TCC(Try-Confirm-Cancel)
原理:
- Try:尝试执行操作,预留资源,但不真正提交。
- Confirm:所有 Try 都成功后,执行最终提交。
- Cancel:如果 Try 失败或某个 Confirm 失败,则执行回滚。
优点: - 业务可控,可以优化事务逻辑,提高性能。
缺点: - 业务代码侵入性强,每个操作都需要实现 Try、Confirm 和 Cancel 逻辑。
- 需要额外的资源预留机制,可能导致资源锁定时间较长。
假设订单跟库存是两个服务。
我理解的两阶段提交,分布式事务,首先 a 想要创建订单就,rpc 到 b 扣库存,扣成功,并记录状态为预扣,然后通知 a 可以创建订单了,a 把订单创建成功了,再把库存扣件日志设置为提交,如果一个库存的记录一直都是预扣状态,超过一段时间,这个库存就会加回去。
这个其实就是 TCC 模型
TCC 更像将下单支付场景,进行了抽象,跟分布式事务并没有直接的联系,分成了尝试下单(try),成功下单(confirm),下单失败(cancel)三种状态,
大多数的支付场景,都有超时未支付自动取消订单的提示
而如果是分布式的场景,即订单服务和库存是两个微服务。这才跟分布式扯上关系。不过依然需要一个事务的协调者,这个时候,其实就跟两阶段提交没啥区别了,两阶段提交会有的问题,TCC 在分布式下也会有
在分布式架构中,需要一个 TCC 事务管理器 来协调订单和库存服务。可以使用:
- Seata(AT/TCC 模式)
- TCC-Transaction
- ShardingSphere-Proxy
- 自定义 TCC 方案
💡 TCC 事务管理器的作用 - 记录全局事务状态(Try、Confirm、Cancel)。
- 监控事务执行情况,确保 Confirm 或 Cancel 成功执行。
- 提供重试机制,确保失败时能够补偿回滚。
5. Saga(长事务模式)
原理:
- 事务被拆分成一系列子事务,每个子事务执行成功后,触发下一个子事务。
- 如果某个子事务失败,需要执行补偿操作(回滚之前的子事务)。
优点: - 适用于长事务场景,如订单、支付等。
- 性能较高,避免了锁竞争。
缺点: - 需要业务层实现补偿逻辑,增加开发复杂度。
- 不适用于强一致性要求的场景。
Saga 跟 TCC 还有两阶段提交不一样的是,saga 是将任务分为一个一个的,然后一个一个的执行,而 TCC 是将任务分成阶段,多个任务在一个阶段一起 try,然后都成功了,再一起 confirm,否则,就一起 cancel
就是很像拆分和竖向拆分的意思,
但是只要涉及到分布式的处理,就需要一个中心化的事务协调者,比如 seata
6. 基于 MQ 的事务消息(可靠事件模式)
原理:
- 事务操作和 MQ 消息发送要么一起成功,要么一起失败。
- 事务提交后,消息发送到 MQ,由消费者执行事务操作。
- 通过 MQ 的回查机制保证消息的可靠投递。
优点:
- 非阻塞,提高性能。
- 可以实现最终一致性。
缺点:
- 依赖消息队列的可靠性。
- 需要处理消息重复消费的问题。
总结
方案 | 一致性 | 事务类型 | 适用场景 | 复杂度 |
---|---|---|---|---|
2PC | 强一致性 | 短事务 | 银行转账等强一致性要求的场景 | 高 |
3PC | 强一致性 | 短事务 | 改进 2PC,但仍有不一致风险 | 高 |
本地消息表 | 最终一致性 | 长事务 | 订单、支付、库存扣减 | 中 |
TCC | 强一致性 | 短事务 | 需要预留资源的事务,如机票预订 | 高 |
Saga | 最终一致性 | 长事务 | 订单、物流等长事务 | 中 |
事务消息(MQ) | 最终一致性 | 长事务 | 高并发、异步场景 | 中 |
不同业务场景适用不同的分布式事务方案,比如:
- 银行交易:需要 2PC 或 TCC 保证强一致性。
- 订单系统:Saga 或本地消息表可以提高性能。
- 高吞吐量的电商场景:事务消息(MQ)适合保证最终一致性。
你目前的业务场景是怎样的?如果需要支持高并发(如 70000QPS),本地消息表、TCC 或 MQ 事务消息可能是更合适的选择。