微服务的分布式事务解决方案
- 1、分布式事务的理论模型
- 1.1、X/Open 分布式事务模型
- 1.2、两阶段提交协议
- 1.3、三阶段提交协议
- 2、分布式事务常见解决方案
- 2.1、TCC补偿型方案
- 2.2、基于可靠性消息的最终一致性方案
- 2.3、最大努力通知型方案
- 3、分布式事务中间件 Seata
- 3.1、AT 模式
- 3.2、Saga 模式
说起微服务的架构,分布式事务是一道绕不开的话题。本文将从分布式事务的理论模型、分布式事务的常见解决方案、分布式事务中间件 Seata的两个常用模式展开说说分布式事务。
1、分布式事务的理论模型
两阶段提交协议、三阶段提交 ,作为 XA 协议解决分布式数据一致性问题的基本原理。
1.1、X/Open 分布式事务模型
X/Open DTP
是 X/Open 定义的一套分布式事务标准,该标准使用两阶段提交
来保证分布式事务的完整性。
X/Open DTP 中包含三种角色
- ① Application(
AP
):指应用程序。 - ② Resource Manager(
RM
):指资源管理器,比如数据库。 - ③ Transaction Manager(
TM
):指事务管理器,事务协调者,负责协调和管理事务,提供AP编程接口或管理RM.
1.2、两阶段提交协议
两阶段提交协议的执行流程:
- ①
准备阶段
:TM 通知 RM 准备分支事务,记录事务日志,并告知 TM 的准备结果。 - ②
提交/回滚阶段
:- 如果所有的 RM 在准备阶段都明确返回成功,则 TM 向所有的 RM 发起事务提交指令,完成数据变更。
- 反之,如果任何一个 RM 明确返回失败,则 TM 会向所有 RM 发送事务回滚指令。
两阶段提交的缺点
:
-
①
同步阻塞
:- 所有参与的 RM 都是事务阻塞型,对于任何一次指令都必须有明确的响应,才能继续进行下一步。
- 否则会处于阻塞状态,占用的资源一直被锁定。
-
②
过于保守
:任何一个节点失败都会导致数据回滚。 -
③
TM 的单点故障
:如果 TM 在第二阶段出现故障,那其他参与的RM 会一直处于锁定状态。 -
④
“脑裂” 导致数据不一致问题
:第二阶段中 TM 向所有的 RM 发送 commit 请求后,发生局部网络异常,导致只要一部分 RM 接收到 commit 请求,进而执行了 commit 操作。另一部分 RM 未收到 commit 请求,从而事务无法提交,导致数据不一致问题发生。
1.3、三阶段提交协议
**三阶段提交协议执行流程
**如下:
-
①
CanCommit
(询问阶段):TM 向 RM 发送事务执行请求,询问是否可以完成指令,RM 只需要回答是或者不是即可,不需要做真正的事务操作,该阶段会有超时中止机制。 -
②
PreCommit
(准备阶段):TM 会根据所有 RM 的反馈结果决定是否继续执行。- 如果在 CanCommit 阶段所有 RM 都返回可以执行操作,则 TM 会向所有 RM 发送 PreCommit 请求,
所有 RM 收到请求后写 redo 和 undo 日志
,执行事务操作但不提交事务
,然后返回 ACK 响应等待 TM 的下一步通知。 - 如果在 CanCommit 阶段,任意 RM 返回不能执行操作的结果,那 TM 会向所有参与者发送事务中断请求。
- 如果在 CanCommit 阶段所有 RM 都返回可以执行操作,则 TM 会向所有 RM 发送 PreCommit 请求,
-
③
DoCommit
(提交或回滚阶段):该阶段根据 PreCommit 阶段执行的结果,来决定 DoCommit 的执行方式。- 如果每个 RM 在 PreCommit 阶段都返回成功,那么 TM 会向所有 RM 发起事务提交指令。
- 如果任何一个 RM 返回失败,那么 TM 会发起中止指令来回滚事务。
相对于二阶段提交协议,三阶段提交协议利用超时机制,解决了同步阻塞问题
。两者的区别如下:
- ① 增加了 CanCommit 阶段,用于询问所有 RM 是否可以执行事务操作并响应,
其目的是可以尽早发现无法执行操作而中止后续的行为
。 - ② 在准备阶段之后,TM 和 RM 都引入了超时机制,
一旦超时TM 和 RM 会继续提交事务,并且认为处于成功状态
,因为在超时情况下事务默认成功的可能性比较大。超时机制避免了资源的永久锁定
。
2、分布式事务常见解决方案
2.1、TCC补偿型方案
TCC
(Try-Confirm-Cancel)是一种两阶段提交的思想
,也是一种比较成熟
的分布式事务一致性解决方案
。TCC 补偿型方案将一个完整事务分为三个步骤:
- ①
Try
:该阶段主要是对数据的校验,或者资源的预留。 - ②
Confirm
:该阶段确认真正执行的任务,只操作 Try 阶段预留的资源。 - ③
Cancel
:该阶段是取消执行,释放 Try 阶段预留的资源。
注意:在某些特殊场景下,比如服务器突然宕机,导致该服务并没有收到 TCC 事务协调器的 Cancel 或者 Confirm 请求,这时 TCC 事务框架会记录一些分布式事务的操作日志,保存分布式事务运行的各个阶段和状态。TCC 事务协调器会根据操作日志进行重试,以达到数据的最终一致性
。
TCC 服务支持接口调用失败发起重试,所以 TCC 暴露的接口都需要满足幂等性
。
2.2、基于可靠性消息的最终一致性方案
RocketMQ 事务消息模型最核心的机制,就是事务回查。下图可以看出,在 RocketMQ 事务消息模型中,事务是由生产者完成。消息队列的可靠性投递机制,保证了消费者如果没有签收消息,消息队列服务器会重复投递。具体可以参考博文 《RocketMQ 顺序消息和事务消息及其原理》 的 【RocketMQ 的事务消息】部分。
2.3、最大努力通知型方案
最大努力通知也被称为定期校对,是以上【基于可靠性消息的最终一致性方案】的优化版,其引入了本地消息表来记录错误消息,然后加入失败消息的定期校对功能,来进一步保证消息被下游系统消费。
最大努力通知方案步骤:
-
第一步:消息由系统A投递到中间件
- ① 业务处理中,操作业务数据入库时,在同一事务中向本地消息表中写一条数据,且数据状态为【未发送】。
- ② 一般采用定时任务,轮询本地消息表中【未发送】状态的数据,将这部分数据发送到消息中间件。
- ③ 消息中间件收到消息后,通过消息中间件的返回应答状态,修改本地消息表状态为【发送成功】。
-
第二步:消息中间件投递到系统B
- ① 消息中间件收到第一步的消息后,同步投递给相应的下游系统,并触发下游系统的业务执行。
- ② 当下游系统业务处理成功后,向消息中间件反馈确认应答,消息中间件便可以将消息删除,从而完成该事务。
- ③ 对于投递失败的消息,利用重试机制进行重试,对于重试失败的,写入错误消息表。
- ④ 消息中间件需要提供失败消息的查询接口,下游系统会定期查询失败消息。
最大努力通知方案缺点:消息表会耦合到业务系统中,如果没有封装好的解决方案,会增加系统的复杂度。
3、分布式事务中间件 Seata
Seata 组件作为一种分布式解决方案,提供了 AT、TCC、Saga 和 XA 事务模型。
3.1、AT 模式
AT 模式是基于 XA 模式演化而来的,AT 和 XA 都是两阶段事务模型
,但是 AT 和XA 相比,做了很多优化
。AT 模式作为 Seata 最主推的分布式事务解决方案。
AT 模式由 TM、RM 和 TC 三大模块组成,其中 TM 和 RM 作为客户端与业务系统(Application)集成,TC 作为 Seata 的服务器独立部署。AT 模式的执行流程:
- ① TM 向 TC 注册全局事务,并生成全局唯一的 XID.
- ② RM 向 TC 注册分支事务,并将其纳入该 XID 对应的全局事务范围。
- ③ RM 向 TC 汇报资源的准备状态。
- ④ TC 汇总所有事务参与者的执行状态,决定分布式事务是全部回滚还是提交。
- ⑤ TC 通知所有 RM 提交/回滚事务。
Seata的AT模式在性能、一致性模型、侵入性、依赖性和灵活性以及配置和部署等方面,相对于XA模式进行了显著的改进
。这些改进使得AT模式成为了一种更加高效、易用和灵活的分布式事务解决方案。
1. 性能提升
资源锁定周期缩短
:XA模式一阶段不提交事务,锁定资源直到二阶段结束才释放,这可能导致性能瓶颈。而AT模式一阶段直接提交事务,不锁定资源,从而缩短了资源锁定周期,提高了系统性能。减少数据库交互
:AT模式通过记录数据快照(undo log)来实现回滚,减少了与数据库的交互次数,进一步提升了性能。
2. 一致性模型
最终一致性 vs 强一致性
:XA模式遵循两阶段提交协议,保证事务的强一致性(满足ACID原则)。而AT模式则通过数据快照和全局锁来实现最终一致性,虽然数据不是实时一致的,但在最终状态上保持一致,这种模型在某些场景下可以接受,并且减少了锁的使用,提高了性能。
3. 侵入性降低
代码侵入性
:XA模式通常需要业务代码显式地参与事务管理,如调用XA接口等。而AT模式则是一种无侵入的分布式事务解决方案,用户只需关注自己的业务SQL,Seata框架会自动处理事务的二阶段提交和回滚操作,降低了对业务代码的侵入性。
4. 依赖性和灵活性
数据库依赖性
:XA模式高度依赖关系型数据库来实现事务的强一致性。而AT模式虽然也依赖数据库,但更多地是通过Seata框架的数据快照和全局锁机制来实现最终一致性,因此对数据库的依赖性和要求相对较低。灵活性
:AT模式提供了更高的灵活性,它支持多种数据库类型(如MySQL、Oracle、PostgreSQL和TiDB等),并且可以根据业务需求进行灵活配置和调整。
3.2、Saga 模式
Saga 模式是一种长事务解决方案
,其核心思想是将一个业务流程中的长事务,拆分成多个本地短事务。业务流程中的每个参与者都提交真实的提交给本地短事务,当其中一个参与者事务执行失败,则通过补偿机制补偿前面已经成功的参于者。
Sage 由一系列 sub-transaction T i 组成,每个 T i 都有对应的补偿动作 C i,补偿动作用于撤销 T i 造成的数据变更结果。每一个 T i 操作都真实的影响数据库。
Sage 模式的两种执行方式:
- T1、T2、T3、 … 、T i :这种方式表示所有事务都正常执行。
- T1、T2、 … 、T j、C j 、… 、C2、C1(其中 0 < j < i):这种方式表示执行到 T j 事务时出现异常,通过补充操作撤销之前所有成功的 sub-transaction.
Sage 提供了两种补偿恢复方式:
- ① 向后恢复:如果任一子事务执行失败,则把之前执行的结果逐一撤销。
- ② 向前恢复:该恢复方式不进行补偿,而是对失败的事务进行重试,其比较适合于事务必须要执行成功的场景。
Saga 的优劣势:
- 和XA 和 TCC 相比,Saga 的一阶段直接提交本地事务,没有锁等待,性能比较高;在事件驱动的模式下,短事务可以异步执行;补偿机制的实现比较简单。
- Sage 的缺点是并不提供原子性和隔离性支持,隔离性的影响比较大。比如 业务中赠送了一张优惠券,若用户将优惠券使用了,且事务如果出现异常要回滚就会出现问题。
.