分布式事务
本节我们简单了解分布式事务的概念及其常见的解决方案
概念
在了解分布式事务前,我们先回顾两个概念
分布式架构:传统系统的架构一般是所有资源(前后端代码、数据库等)都统一放到同一个计算机上面,而分布式架构就是区别于这种架构的,即程序和数据通过网络分布在多于一个的计算机上的架构。
事务:一个包含多个步骤的业务操作,这些步骤要么全部成功,要么全部失败。
那分布式事务的概念其实很容易理解:一个分布在多于一个计算机(节点)上且包含多个步骤的业务操作,这些步骤要么全部成功,要么全部失败。分布式事务是用于分布式系统中保证不同节点之间的数据一致性。
举个简单的例子:在一个电商系统中,顾客下单后需要扣减库存并且用户得到积分,如果订单服务、库存服务、积分服务都是互相独立的服务,那么在生成订单的时候需要保证订单系统的事务正确提交,也需要同时保证库存服务和积分服务的事务正确提交。
分布式事务解决方案
XA 协议
在了解各个分布式事务解决方案前,先简单了解一下分布式事务中一个非常著名的协议:XA 协议,后面提到的各种解决方案都是基于这个协议开展的。
XA 协议中划分了两个角色:
- 事务管理者:一个全局调度的角色,决定了本次事务成功或失败。
- 资源管理者:负责执行事务的角色。
2PC (两阶段提交)
两阶段提交是 XA 协议的一个实现
总体上的流程分成了两个阶段:
准备阶段:事务管理者向所有资源管理者发送事务内容,资源管理者执行事务但不提交,并询问各资源管理者是否可以提交事务。

提交阶段:事务管理者根据准备阶段中得到的反馈消息,决定本次事务是
Commit状态还是Rollback状态,并向所有每个资源管理者发送具体事务状态的指令,所有资源管理者根据事务管理者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。只有全部服务都成功执行事务,本次事务才能提交;只要有一个服务执行事务失败,那么所有服务都需要回滚事务。
优点:使用简单、对业务侵入小。
缺点:
- 不可靠:事务管理者一旦发生单点故障,所有资源管理者都进入阻塞锁定资源的状态,特别是处于第二阶段。
- 性能问题:在第一阶段中首先成功执行事务的资源管理者需要等待其他资源管理者执行事务,等待的过程也是阻塞的。
- 数据不一致:事务管理者在第二阶段时向所有资源管理者发送
Commit消息时,发生局部网络故障时,部分资源管理者未能正确接受Commit消息执行Commit操作,分布式系统便出现数据不一致的现象。
3PC(三阶段提交)
3PC 是对 2PC 的升级,主要的升级有两个地方:
引入超时机制。在事务管理者和资源管理者都引入超时机制:
- 当资源管理者在一定时间内没有收到事务管理者的
Commit消息,那么就会自动提交事务,不会阻塞等待,避免当事务管理者宕机时一直锁定资源阻塞等待。 - 当事务管理者长时间没有收到各资源管理者执行事务的 ACK 消息,那么会执行中断事务。
- 当资源管理者在一定时间内没有收到事务管理者的
在第一阶段和第二阶段中插入一个准备阶段。保证在最后提交阶段前各个资源管理者的状态时一致的。
3PC 包含了三个阶段:
CanCommit:
- 事务管理者向所有资源管理者发送 CanCommit 消息,询问是否可以执行事务提交,进入等待状态。
- 资源管理者如果认为自己可以顺利执行事务,那么就返回 Yes 消息,并进入预备状态;反之返回 No 消息。
PreCommit:
如果 CanCommit 阶段所有资源管理者都返回了 Yes,那就执行事务预执行。
- 事务管理者向所有资源管理者发送 PreCommit 消息,进入等待状态。
- 资源管理者执行事务操作,但是不提交事务,返回 ACK 响应。
如果 CanCommit 阶段有任意一个资源管理者返回了 No,或者事务管理者等待超时,那就执行事务中断。
- 事务管理者向所有资源管理者发送 Abort 消息。
- 资源管理者收到消息后或等待消息超时就执行事务的中断。
DoCommit:
如果 PreCommit 阶段接收到的 ACK 响应都是事务成功执行的响应,那么进入提交状态。
- 事务管理者向所有资源管理者发送 DoCommit 消息,进入等待状态。
- 资源管理者提交事务,并释放执行事务中所定的资源,返回 ACK 响应。
如果 PreCommit 阶段接收到任意一个 ACK 响应是失败或者事务管理者等待超时,那么执行事务中断。
- 事务管理者向所有资源管理者发送 Abort 消息。
- 资源管理者回滚事务,并释放执行事务中所定的资源,返回 ACK 响应。
如果资源管理者等待事务管理者消息时等待超时,默认会执行事务的提交。

优点:解决了 2PC 的单点故障的问题,减少阻塞,资源管理者一旦等待事务管理者的协调消息超时时,会默认执行事务提交。
缺点:数据一致性的问题一直存在,事务管理者向各资源管理者发送 Abort 消息时,可能由于局部的网络影响,部分资源管理者没有成功收到这个消息,等待超时时会默认提交事务,导致各服务间的数据不一致。
TCC(事务补偿)
刚刚提到的 2PC、3PC 都是面向数据库层面的解决方案,而 TCC 是面向业务层面的解决方案。
TCC 与 2PC 的区别:2PC 是面向数据库层面的,TCC 更像是 2PC 在业务层的实现。
使用 TCC 时,必须实现 3 个接口
- Try:对业务系统做检测及资源预留。系统会将需要确认的资源预留、锁定,确保确认操作一定能执行成功。
- Confirm:确认执行业务操作。
- Cancel:负责回滚事务操作。系统将撤消之前预留的资源,也就是撤消已执行的预留操作对系统产生的影响。
优点:
- 性能提升:使用具体业务来控制资源,使得锁粒度下降,不会锁定整个资源。
- 数据一致性:给予 Confirm 和 Cancel 的幂等性,保证事务最终能正确提交或回滚。
缺点:TCC 是业务层的解决方案,对业务代码耦合度高,提高开发与维护的成本。
RocketMQ 事务消息
以支付订单后奖励积分为例,此时生产者是订单系统,消费者是积分系统,当积分系统收到订单系统传来订单支付成功,那么就给用户提供积分的奖励。
RocketMQ 事务消息的流程如下:

- 订单系统会发送一条 half 消息到 RocketMQ 中,这个 half 消息其实是一个代表订单成功支付的消息,只不过目前这个状态积分系统是无法感知这个消息的存在的。
- 如果收到 MQ 的响应,那么订单系统就可以进行自己的业务,比如更新订单状态;如果发送 half 消息后没有收到 MQ 的响应,那么可以认定 MQ 此时有问题,那么就在订单系统中「回滚」这笔订单,例如订单关闭或者发起退款。
- 如果业务逻辑成功执行、本地事务成功提交,那么就发送一个
commit请求到 MQ 中,MQ 收到commit请求后,之前的 half 消息也就对积分系统可见了;如果在处理自己系统的业务时,本地事务发生异常了,那么就发送一个rollback请求到 MQ 中,让 MQ 删除之前发送的 half 消息;如果业务逻辑的事务状态为unknown,那么 MQ 就会发起回查,回查生产者本地事务的状态。 - 假设由于网络波动、生产者重启导致事务消息的二次确认丢失,MQ 也有补偿措施,它会去扫描自己处于 half 状态的消息,如果这个 MQ 一直没有接收到对这个 half 消息执行
rollback或commit的命令,会回调一个接口,询问这个订单是什么状态 ,此时订单系统就可以查询这个订单的状态,如果是成功了,那么就发送一个commit请求;否者发送rollback请求
RocketMQ 事务消息有两大核心:
- 两阶段提交、半消息(Half 消息):Broker 只有收到第二阶段的消息,消费者才能拉取
- 事务补偿机制:当 Broker 收到状态为
Unknown的消息时,或者由于网络波动、生产者宕机导致长时间没有收到第二阶段提交,会触发事务回查机制
优点:实现了最终一致性,不需要依赖本地数据库事务,对业务侵入低。
缺点:引入中间件可能导致系统复杂度提升。
(其实没什么大缺点,推荐使用)
参考链接