分布式事务的解决方案有很多,比如:2PC、3PC、TCC、Saga、事务消息和本地消息表等等。这些方法,它的强项和弱项都不一样,适用的场景也不一样,所以最好这些分布式事务都能够掌握,这样才能在面临实际问题的时候选择合适的方法。这里面,2PC 和本地消息表这两种分布式事务的解决方案,比较贴近于我们日常开发的业务系统。
1. 两阶段提交协议(2PC,Two - Phase Commit)
-
原理
- 准备阶段(Prepare Phase) :协调者(Coordinator)向所有参与者(Participant)发送事务准备请求,参与者接收到请求后,执行事务操作并将操作结果反馈给协调者。如果参与者能够成功执行事务操作,则返回 “同意”,否则返回 “中止”。
- 提交阶段(Commit Phase) :如果所有参与者都返回 “同意”,协调者向所有参与者发送提交请求,参与者执行提交操作;如果有任何一个参与者返回 “中止”,协调者向所有参与者发送回滚请求,参与者执行回滚操作。
-
优点
- 实现简单,理论上能够保证数据的强一致性。
-
缺点
- 同步阻塞:在整个事务执行过程中,参与者会一直阻塞,直到收到协调者的最终指令,这会导致系统性能下降。
- 单点故障:协调者是整个协议的核心,如果协调者出现故障,可能会导致整个事务无法正常完成。
- 数据不一致:在提交阶段,如果协调者发送提交请求后出现故障,部分参与者可能已经提交,而部分参与者未收到请求,从而导致数据不一致。
2. 三阶段提交协议(3PC,Three - Phase Commit)
-
原理
- 询问阶段(CanCommit) :协调者向参与者发送询问请求,询问参与者是否有能力执行事务操作。参与者根据自身情况返回 “可以” 或 “不可以”。
- 准备阶段(PreCommit) :如果所有参与者都返回 “可以”,协调者向参与者发送预提交请求,参与者执行事务操作并将操作结果反馈给协调者。如果参与者能够成功执行事务操作,则返回 “就绪”,否则返回 “中止”。
- 提交阶段(DoCommit) :如果所有参与者都返回 “就绪”,协调者向所有参与者发送提交请求,参与者执行提交操作;如果有任何一个参与者返回 “中止”,协调者向所有参与者发送回滚请求,参与者执行回滚操作。
-
优点
- 相比 2PC,3PC 减少了参与者的阻塞时间,在一定程度上提高了系统的并发性能。
- 通过引入询问阶段,降低了单点故障对系统的影响。
-
缺点
- 实现复杂度较高。
- 仍然无法完全避免数据不一致的问题。
3. 补偿事务(TCC,Try - Confirm - Cancel)
-
原理
- Try 阶段:尝试执行业务操作,完成所有业务检查(一致性),预留必需的业务资源(隔离性)。例如,在一个电商系统中,用户下单时,Try 阶段会检查库存是否充足,并预留相应的库存。
- Confirm 阶段:如果所有参与者的 Try 阶段都成功,则执行 Confirm 操作,使用 Try 阶段预留的资源完成业务处理。Confirm 操作要保证幂等性,即多次执行的结果与一次执行的结果相同。
- Cancel 阶段:如果任何一个参与者的 Try 阶段失败,则执行 Cancel 操作,释放 Try 阶段预留的资源。Cancel 操作也要保证幂等性。
-
优点
- 性能较高,因为在 Try 阶段完成了资源的预留,后续的 Confirm 和 Cancel 阶段可以快速执行。
- 可以实现自定义的业务补偿逻辑,适用于复杂的业务场景。
-
缺点
- 实现复杂度较高,需要开发者手动编写 Try、Confirm 和 Cancel 三个阶段的代码。
- 对业务的侵入性较强,需要对业务代码进行较大的改造。
4. 本地消息表
-
原理
- 消息记录:业务系统在执行本地事务时,同时将消息记录到本地消息表中。例如,在一个订单系统中,当创建订单时,会将订单相关的消息插入到本地消息表中。
- 消息发送:本地事务提交后,通过定时任务或者消息队列的重试机制,将消息发送到消息队列中。
- 消息消费:下游系统从消息队列中消费消息,并执行相应的业务操作。如果消费失败,会进行重试,直到消费成功。
-
优点
- 实现简单,对业务系统的侵入性较小。
- 基于消息队列的异步处理,提高了系统的并发性能。
-
缺点
- 依赖于本地消息表和消息队列的可靠性,如果消息表或消息队列出现故障,可能会导致消息丢失或重复消费。
- 需要处理消息的重试和幂等性问题。
5. 最大努力通知
-
原理
- 业务处理:业务系统在完成业务操作后,向通知系统发送通知消息。
- 通知发送:通知系统接收到消息后,会尽最大努力向目标系统发送通知。通知系统会记录通知的状态,并进行重试,直到达到最大重试次数。
- 业务验证:目标系统接收到通知后,会进行业务验证,如果验证通过,则执行相应的业务操作。
-
优点
- 实现简单,对业务系统的侵入性最小。
- 系统的耦合度较低,各个系统之间可以独立开发和部署。
-
缺点
- 数据一致性较弱,只能保证最终一致性。
- 需要处理通知的重试和幂等性问题。
6. 基于消息队列的最终一致性方案
-
原理
- 生产者发送消息:业务系统(生产者)在执行本地事务前,先将消息发送到消息队列的事务消息服务中。事务消息服务会将消息标记为 “待确认” 状态,此时消息不会被消费者消费。
- 本地事务执行:生产者执行本地事务,如果本地事务执行成功,则向事务消息服务发送 “确认” 消息;如果本地事务执行失败,则发送 “回滚” 消息。
- 消息投递:事务消息服务根据生产者的反馈,将消息标记为 “可消费” 状态,并将消息投递到消息队列中。消费者从消息队列中消费消息,并执行相应的业务操作。
-
优点
- 实现相对简单,通过消息队列的异步处理,提高了系统的并发性能。
- 可以保证数据的最终一致性。
-
缺点
- 依赖于消息队列的可靠性,如果消息队列出现故障,可能会导致消息丢失或重复消费。
- 需要处理消息的重试和幂等性问题。