分布式八股分析

分布式

1.分布式事务设计

TCC、Saga、本地消息表、事务消息

本地消息表

这是一种实现“最终一致性”的常用方案,核心思想是将业务操作和发送消息这两个步骤,放在同一个本地事务里来保证原子性。

  1. 事务发起方:在执行核心业务逻辑时(例如:创建订单),会在同一个数据库事务中,向一张本地的“消息表”插入一条消息记录,这条记录的状态初始为“待发送”。
  2. 事务提交:当本地事务成功提交后,订单数据和“待发送”的消息记录会同时落库。
  3. 消息投递:我会用一个独立的、可靠的后台任务(比如使用定时任务调度框架如XXL-Job)去轮询这张消息表,把所有“待发送”状态的消息发送到消息队列(MQ)中。
  4. 状态确认:消息成功投递到MQ后,后台任务会更新消息表中的记录状态为“已发送”或直接删除。如果投递失败,它会进行重试。
  5. 事务消费方:下游服务消费MQ中的消息,并执行相应的业务逻辑。为了防止重复消费,消费方必须保证接口的幂等性。

消息的发送不是实时的,存在一定的延迟。需要额外维护一个后台任务。

事务消息

  1. 第一阶段 (Prepare Message):生产者先向MQ Server发送一条“半消息”或“预备消息”。这条消息对消费者是不可见的。
  2. 第二阶段 (执行本地事务):发送“半消息”成功后,生产者开始执行本地的数据库事务。
  3. 第三阶段 (Commit/Rollback):
    • 如果本地事务成功,生产者会向MQ Server发送一个Commit指令,MQ Server收到后会将之前的“半消息”标记为可投递,消费者此时才能消费到。
    • 如果本地事务失败,生产者会发送一个Rollback指令,MQ Server会删除这条“半消息”。
  4. 超时回调检查:如果生产者在执行完本地事务后宕机,没有发送CommitRollback指令,MQ Server会在超时后,主动回调生产者应用提供的一个接口,来查询该事务的最终状态,并根据查询结果来决定是Commit还是Rollback

需要消息中间件本身支持事务消息这个特性

TCC (Try-Confirm-Cancel)

  1. Try阶段:这是准备阶段。对各个服务的资源进行检查和预留。比如,库存服务Try阶段就是冻结指定数量的库存,而不是直接扣减。
  2. Confirm阶段:如果所有服务的Try阶段都成功,协调器就会调用所有服务的Confirm方法,执行真正的业务逻辑。比如,库存服务Confirm阶段就是将之前冻结的库存进行扣减。
  3. Cancel阶段:如果任何一个服务的Try阶段失败,协调器会调用所有已经执行过Try成功的服务的Cancel方法,释放预留的资源。比如,库存服务Cancel阶段就是解冻之前冻结的库存。
  • 优点:性能较高,因为它不像2PC那样在整个事务过程中都持有锁。能够实现数据的强一致性。
  • 缺点:对业务代码的侵入性非常强,开发成本高,每个业务操作都需要实现Try-Confirm-Cancel三个接口,并且要保证它们的幂等性。

Saga

Saga是一种长事务解决方案,核心思想是将一个大的分布式事务拆分成一系列的本地事务,由Saga事务协调器来协调。如果某个步骤失败,则会调用前面已执行步骤的补偿操作。

  • 一个Saga由一系列子事务 T1, T2, ..., Tn 组成。
  • 每个子事务 Ti 都有一个对应的补偿事务 Ci
  • 执行顺序是 T1, T2, ..., Tn。如果其中任意一个 Ti 失败,则会按逆序执行补偿事务 C(i-1), ..., C2, C1

  • 优点:适用于长流程、业务复杂的场景,一阶段提交,没有锁,系统吞吐量高。

  • 缺点:不保证事务的隔离性,因为在补偿发生前,其他事务可能已经看到了T1,T2等操作产生的不一致的中间状态。