说明:
本文内容是对自己学习分布式事务的一个总结,有些内容来源于网络,如有侵权,请联系本人删除。
文中可能存在理解错误的地方,欢迎留言指正、探讨,不喜勿喷,谢谢。
如果您以前了解过分布式事务相关的模型,那么本文对您可能没有太大的参考价值。
阅读本文需要先了解一些事务与分布式相关的理论基础,例如什么是事务,事务的ACID特性,CAP理论,BASE理论等等。
㈠ 什么是分布式事务
分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
一个分布式事务由多个本地事务组成,这些本地事务分布在不同的服务节点,甚至不同的应用,分布式事务需要保证这些本地事务要么全部成功,要么全部失败。
个人开发过程中遇到的分布式事务场景主要有分库分表和微服务化两种:
- 分库分表
一个数据库中的数据量比较大或者预期未来的数据量比较大,对数据库和表进行水平拆分。
分库的场景我们项目中直接使用ShardingJDBC来处理分布式事务,当然,ShardingJDBC也是通过整合其他分布式事务框架来解决的。
如果仅仅是分表,则无需考虑分布式事务的问题。
- 微服务化
业务拆分成独立的服务,服务之间通过RPC框架或者HTTP请求进行远程调用,实现服务之间的通信。
分布式事务相比本地事务,要复杂很多,主要体现在:
- 事务链路被延长: 对于本地事务,所有与事务相关的操作都封装在一个Service方法中。而对于分布式事务,各个本地事务分布在不同的服务节点,事务链路被延长,依靠网络通信组成一个整体。
- 网络通信的不稳定性: 事务从单个节点变成了多个节点之间的网络通信,而网络通信可能出现三种情况:成功、失败、超时。如果网络通信超时,事务发起方无法知道事务被动方是否成功处理了请求,导致出现非常复杂的情况。
- 存储端的多样性: 在分布式事务中,存储端可能不仅仅只有数据库,还会有Redis、MQ等中间件。
㈡ 分布式事务分类
分布式事务根据实现方式一般可分为刚性事务、柔型事务两大类。
刚性事务: 满足CAP理论的CP方案。通常无业务改造,强一致性,原生支持回滚/隔离性,但是并发能力较低,比较适合短事务。
刚性事务使分布式事务,像本地式事务一样,具备数据强一致性。但由于同步阻塞,处理效率低,不适合高并发的场景。
柔性事务: 满足BASE理论(AP方案的延伸)。不追求强一致性,而是追求最终一致性,允许数据存在中间状态。
柔性事务有两个特性:基本可用和柔性状态。
基本可用是指分布式系统出现故障的时候允许损失一部分的可用性。
柔性状态是指允许系统存在中间状态,这个中间状态不会影响系统整体的可用性,比如数据库读写分离的主从同步延迟等。柔性事务的一致性指的是最终一致性。
与刚性事务相比,柔性事务需要进行业务改造,实现业务实现资源锁定,补偿等等。适合高并发场景。
部分布式事务模型:
㈢ 刚性事务
刚性事务一般是根据XA协议实现的。
⑴ XA协议
XA规范是X/Open组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,与语言无关。
XA规范描述了全局事务管理器(TM, Transaction Manager)与局部资源管理器(RM, Resource Manager)之间双向通信的接口,在TM与多个RM之间形成一个双向通信桥梁。
XA规范的目的是允许多个资源管理器(如数据库)在同一事务中访问,从而在多个资源管理器下保证ACID特性。目前常见的数据库,如Oracle, Mysql(InnoDB)等,都是实现了XA接口的,都可以作为RM。
实现了XA规范的模型叫做XA模型或者X/Open DTP模型,在XA模型里面,有三个角色:
AP
: Application,应用程序,一般是指业务层。哪些操作属于同一个事务,由AP编排。TM
: Transaction Manager,事务管理器。接收AP的事务请求,对全局事务进行管理,管理各个小事务的状态,协调RM的处理,是整个事务调度模型的核心部分。RM
:Resource Manager,资源管理器。一般是数据库,也可以是其他的资源管理器,如MQ,文件系统等。
XA之所以需要引入事务管理器,是因为在分布式系统中,多台机器理论上无法达到一致的状态,需要引入一个单点进行协调。事务管理器控制着全局事务,管理事务生命周期,并协调资源。
⑵ JTA协议
JTA
(Java Transaction API即Java事务API)是Java定义的一套用于分布式事务管理的规范,JTA实现了XA模型。
JTA定义了一套接口,接口定义了事务角色之间需要遵守的约定。
Java还定义一套各个事务角色之间如何进行交互的规范JTS
(Java Transaction Service即Java事务服务)。
JTA定义了一个框架,框架中有多个角色,JTS则是定义了这些角色应该怎样进行交互。
像很多其他的java规范一样,JTA仅仅定义了接口,具体的实现则由供应商负责。
常见的JTA实现有如下几种:
-
Atomikos
Atomikos提供两个分布事务产品:
TransactionEssentials:开源的免费产品
ExtremeTransactions:商业版,需要收费
从上图可以看出,在开源版本中支持JTA/XA、JDBC、JMS的事务。
官网地址:https://www.atomikos.com/ -
Narayana
Narayana是Jboss团队提供的XA分布式事务的解决方案。它具有以下特点:
① 基于JTA实现。
② TransactionManager(TM)完全去中心化设计,与业务耦合,无需单独部署。
③ 事务日志支持数据库存储,支持集群模式下的事务恢复。
官网地址:https://www.narayana.io/ -
Bitronix
从GitHub上面的源码来看,好像有很久没更新了,但是它有SpringBoot对应的starter包spring-boot-starter-jta-bitronix
GitHub:https://github.com/bitronix -
JOTM
JOTM (Java Open Transaction Manager)是由ObjectWeb协会开发的功能完整的且开源的事务管理器。这个好像也没更新了。
官网地址:http://jotm.ow2.org/
Spring支持JTA模式的分布式事务管理,Spring事务管理器的PlatformTransactionManager
接口有如下两个实现类:
DataSourceTransactionManager
:用于实现本地事务管理JtaTransactionManager
:用于实现分布式事务管理
⑶ 2PC
2PC即Two-Phase-Commit
,二阶段提交,是一个标准的XA模型。
2PC解决的是分布式数据强一致性问题,两阶段提交在处理分布式事务时分为两个阶段:
准备阶段
(prepare,又叫投票阶段,提交事务请求阶段)和提交/回滚阶段
(commit/rollback)。
2PC中存在两个角色,事务协调者
和事务参与者
。协调者负责协调多个参与者之间的事务,协调者先询问各个参与者是否可以执行事务,如果每个协调者都回复YES,那么就正式提交每个协调者上的事务;如果任何一个协调者回复NO或者超时,那么就回滚每个协调者上的事务。
2PC 处理分布式事务的流程:
阶段一:准备阶段
- 事务询问。协调者向所有参与者发送事务内容,询问是否可以执行提交操作,并等待各个参与者反馈结果;
- 执行事务。各参与者收到事务内容后,执行本地事务,并写Undo和Redo事务日志,
锁定资源,但是不会提交
; - 各个参与者向协调者反馈事务执行情况。成功执行返回Yes,否则返回No。
阶段二:提交/回滚阶段
协调者在阶段二决定是否最终执行事务提交操作。包含两种情形:
第一种情形:所有参与者都回复Yes,那么执行事务提交。
- 发送提交请求。协调者向所有参与者发送Commit请求;
- 事务提交。参与者收到Commit请求后,正式执行事务提交操作,释放锁定的资源;
- 反馈提交结果。参与者在完成事务提交后,向协调者返回Ack消息确认;
- 完成事务。协调者在收到所有参与者的Ack消息后,完成事务提交。
第二种情形:至少一个参与者回复No,或者协调者等待超时,那么协调者将会中断事务。
- 发送回滚请求。协调者向所有参与者发送Rollback请求;
- 事务回滚。参与者收到Rollback请求后,利用本机Undo日志,执行Rollback操作,释放锁定的资源;
- 反馈回滚结果。参与者在完成回滚操作后,向协调者发送Ack消息;
- 中断事务。协调者收到所有参与者的回滚Ack消息后,完成事务中断。
2PC的缺点:
- 参与者同步阻塞问题
在分布式事务的执行过程中,所有参与者都处于事务阻塞状态,占用着数据库资源,只有当所有参与者准备完毕,事务协调者才会通知进行全局提交,参与者进行本地事务提交后才会释放资源。这个过程可能会比较长,对性能影响比较大。 - 协调者单点故障问题
事务协调者是整个2PC模型的核心,一旦事务协调者发生故障,会导致事务参与者收不到提交或回滚指令,从而导致事务参与者无法继续完成事务,无法释放锁定的资源,一直处于阻塞状态。 - 请求丢失导致数据不一致问题
在第二个阶段,如果发生局部网络故障,导致部分参与者与协调者无法进行网络通信,这会导致只有一部分事务参与者能收到提交消息,进行事务提交,而另一部分没有收到提交消息的事务参与者无法提交事务,这就导致了整个分布式系统出现数据不一致的问题。 - 缺乏较好的容错机制
当参与者出现故障时,协调者无法快速得知,只能依赖超时来决定执行事务提交还是事务中断。
2PC方案比较适合单个应用里,跨多个库的分布式事务,而且因为严重依赖于数据库层面来搞定复杂的事务,效率很低,绝对不适合高并发的场景。
有哪些实现了2PC方案的框架?
-
阿里巴巴Seata的AT/XA模式是基于2PC实现的。AT模式则是两阶段提交协议的演变,没有一直锁住资源。具体可以进入官网学习一下,中文版的,学习起来很方便。
Seata官网:https://seata.io/zh-cn/ -
TX-LCN也实现2PC方案,LCN名称是各取如下单词首字母得来的:锁定事务单元(lock)、确认事务状态(confirm)、通知事务(notify)。
TX-LCN定位于一款事务协调性框架,框架其本身并不生产事务,而是本地事务的协调者,从而达到事务一致性的效果。
官方文档:https://www.codingapi.com/docs/txlcn-preface/
GitHub:https://github.com/codingapi/tx-lcn
⑷ 3PC
针对2PC的缺点,研究者提出了3PC,即Three-Phase-Commit
。
3PC作为2PC的改进版,将2PC的两阶段过程,重新划分为
事务询问
(CanCommit)、预提交
(PreCommit)和执行提交
(DoCommit)三个阶段。
3PC处理分布式事务的流程:
阶段一:CanCommit
- 事务询问。协调者向所有参与者发送包含事务内容的CanCommit的请求,询问是否可以执行事务提交,并等待应答;
- 各参与者返回事务询问结果。如果参与者认为可以顺利执行事务,则返回Yes,否则返回No。此阶段,参与者并没有执行事务,也就不会锁定资源。
阶段二:PreCommit
协调者根据阶段一的反馈情况决定是否可以执行PreCommit操作。有以下两种情形:
第一种情形:所有的事务参与者都返回Yes,则执行事务预提交
- 发送预提交请求。协调者向所有参与者发出PreCommit请求,并进入准备完成阶段;
- 事务预提交。参与者收到PreCommit请求后,会执行事务操作,并将Undo和Redo日志写入本机事务日志,
锁定事务资源,但是不会提交
; - 各参与者返回事务执行结果。参与者的本地事务执行成功则向协调者返回Yes,否则返回No,同时等待最终的Commit或Abort指令。
第二种情形:至少一个参与者返回No,或者等待超时,则执行事务中断
- 发送中断请求。协调者向所有参与者发送Abort请求;
- 中断事务。无论是收到协调者的Abort请求,还是参与者等待协调者的指令时出现超时,参与者都会中断事务。注意,这种情形下,事务还是没有执行,所以不需要回滚。
阶段三:DoCommit
在这个阶段,会真正的进行事务提交,同样存在两种情形。
第一种情形:所有事务参与者都返回PreCommit成功的Ack响应,那就执行事务提交
- 发送提交请求。协调者向所有参与者发送DoCommit请求;
- 事务提交。参与者收到DoCommit请求后,会正式执行事务提交操作,并在完成提交操作后释放占用的资源;
- 反馈事务提交结果。参与者将在完成事务提交后,向协调者发送Ack消息;
- 完成事务。协调者接收到所有参与者的Ack消息后,完成事务。
情形二:至少一个参与者返回PreCommit失败的Ack响应,或者等待超时,则执行事务中断
- 发送中断请求。协调者向所有的参与者发送Abort请求;
- 事务回滚。参与者收到Abort请求后,会利用阶段二中的Undo日志执行事务回滚,并在完成回滚后释放占用的资源;
- 反馈事务回滚结果。参与者在完成回滚后向协调者发送Ack消息;
- 中断事务。协调者接收到所有参与者反馈的Ack消息后,完成事务中断。
3PC相对于2PC做了哪些改进呢?
- 3PC把2PC协议的第一个阶段拆分成了两步:先询问,再锁资源。
- 3PC在
协调者和参与者中都引入超时机制
,而2PC只有协调者才有超时机制。3PC的参与者在阶段一和阶段二返回响应后,若等待下一个阶段的指令超时,会自动中断事务,避免了参与者在长时间无法收到协调者指令的情况下,无法释放资源的问题,降低了阻塞范围。
但是,3PC仍然没有解决数据不一致的问题。
参与者收到PreCommit指令后,执行事务;如果由于网络通信问题,导致在DoCommit阶段,参与者没有及时接收到来自协调者的DoCommit指令,会在等待超时之后,自动进行事务的提交;这种机制在阶段三如果协调者发送的是Abort指令,那么接收到指令的参与者会进行事务回滚,而没有收到指令的参与者会进行事务提交,此时就会造成数据的不一致。
在阶段三,参与者超时自动进行事务提交的设计,应该是基于概率决定的。只有所有的参与者在阶段一都回复了Yes,同意执行事务后;事务协调者才会发送PreCommit指令,一旦参与者收到了PreCommit指令,即使没有收到阶段三的指令,那么它就认为其它参与者都能执行成功的概率较大。
XA规范在1994年就出现了,至今没有大规模流行起来,必然是因为有一定的缺陷:
- 数据锁定:数据在事务未结束前,为了保障一致性,根据数据隔离级别进行锁定。
- 协议阻塞:本地事务在全局事务没commit或rollback前都是阻塞等待的。
- 性能损耗高:主要体现在事务协调增加的RT成本,并发事务数据使用锁进行竞争阻塞。
XA最大的缺点就是性能不理想,无法满足高并发场景。
㈣ 柔性事务
柔性事务可分为补偿型和异步通知型两种。
⑴ 补偿型事务
补偿型又可以分为TCC和Saga两种模式。
补偿模式使用一个额外的协调服务来协调各个需要保证一致性的业务服务,协调服务按顺序调用各个业务服务,如果某个业务服务调用异常,就取消之前所有已经调用成功的业务服务。
补偿是一个独立的支持ACID特性的本地事务,用于在逻辑上取消服务提供者上一个ACID事务造成的影响。
TCC
TCC(Try-Confirm-Cancel)分布式事务模型是一个二阶段补偿型事务模型,TCC把事务分成Try
、Confirm
/Cancel
两个阶段。
TCC分布式事务模型不依赖资源管理器(RM)对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。 资源的锁定与释放完全由业务代码控制,避免了长事务,可以获取更高的性能。
TCC模型包括三部分:
- 主业务服务:事务的发起方,事务的编排者,负责发起并完成整个业务活动。
- 从业务服务:事务的所有参与方,负责提供TCC业务操作,实现资源预留(Try)、确认(Confirm)、取消(Cancel)三个接口。
- 事务管理器:控制整个业务活动,包括记录维护TCC全局事务的事务状态和每个从业务服务的子事务状态。
TCC分布式事务模型的工作流程
TCC模型认为对于业务系统中一个特定的业务逻辑,其对外提供服务时,必须接受一些不确定性,即对业务逻辑初步操作(Try)的调用仅是一个临时性操作,调用它的主业务服务保留了后续的取消权。如果主业务服务认为全局事务应该回滚,它会要求取消之前的临时性操作,这就对应从业务服务的取消操作(Cancel)。而当主业务服务认为全局事务应该提交时,它会放弃之前临时性操作的取消权,这对应从业务服务的确认操作(Confirm)。每一个初步操作,最终都会被确认或取消。
TCC分布式事务模型各阶段的业务逻辑:
- Try:尝试执行业务,
完成所有业务检查,预留必须的业务资源
。 - Confirm:对业务做确认提交,执行真正的业务逻辑,
不作任何业务检查,只使用Try阶段预留的业务资源
。因此,只要Try操作成功,Confirm必须能成功。另外,Confirm操作需满足幂等性,保证一个分布式事务有且只能成功一次。 - Cancel:在业务执行错误时,执行业务取消,
释放Try阶段预留的业务资源
。同样的,Cancel操作也需要满足幂等性。
Try阶段失败可以Cancel,如果Confirm和Cancel阶段失败了怎么办?
TCC中会添加事务日志,如果Confirm或者Cancel阶段出错,则会进行重试,所以这两个阶段需要支持幂等;如果重试失败,则需要人工介入进行恢复和处理等。
TCC分布式事务模型需要满足哪些要求?
- 允许空Cancel:事务管理器在调用从服务的Try接口时,由于网络请求超时,可能会丢失请求,导致从服务并没有收到Try请求,由于请求超时,事务管理器触发取消操作,从服务此时收到了Cancel请求。从服务服务在未收到Try请求的情况下收到Cancel请求,这种场景被称为空Cancel;TCC的从服务在实现时应当允许空Cancel的执行。
- 防悬空:在极端情况下,事务管理器在调用从服务的Try接口时,由于网络拥挤导致事务管理器请求超时,此时事务管理器触发Cancel操作;Cancel之后,从服务却收到了Try请求,于是从服务出现了二阶段Cancel请求比一阶段Try请求先执行的情况。从服务需要拒绝执行空回滚之后到来的一阶段Try请求。
- 幂等性:无论是请求重复还是失败重试,从服务的Try、Confirm和Cancel都有可能被重复执行,从服务必须保证执行多次与执行一次产生的结果相同。
有哪些实现了TCC分布式事务模型的框架?
- Seata的TCC模式。
- TX-LCN的TCC模式。
- Hmily的TCC模式。
网上说Seata的TCC模式不支持Spring Cloud,有些同学建议使用Hmily。
Hmily号称是一款金融级别的分布式事务解决方案,将来还会支持XA模式。
官网地址:https://dromara.org/zh/projects/hmily/overview/
GitHub:https://github.com/dromara/hmily
2PC与TCC的比较
2PC也是一个二阶段事务模型,TCC是一个补偿型二阶段事务模型,二者经常用来做比较。
- 事务的处理方式不同。2PC是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁,如果有其他事务需要更新这些记录,那么就必须等待锁释放。TCC是业务层面的分布式事务,最终一致性,每个步骤都是独立的本地事务,不会一直持有资源的锁,性能较好。
- 代码侵入性的比较。2PC的内部过程对开发者屏蔽,开发者从代码层面是感知不到这个过程的。TCC对代码的侵入性强,每个从服务都必须实现try、confirm、cancel3个接口,开发成本高,今后维护改造的成本也高。
- 数据库方面的比较。2PC需要数据库支持XA协议以及支持ACID特性;而TCC数据库无须支持XA协议,只需支持ACID特性即可。
- 模型角色的比较。2PC分为AP、TM、RM;TCC分为主业务服务、TCC事务管理器、从业务服务。AP与主业务服务对应,RM与从业务服务对应。
- 模型接口比较。2PC中的RM提供prepare、commit、rollback接口;TCC从业务服务提供try、confirm、cancel接口。接口也可以相互对应起来。
- 阶段一的操作比较。2PC的RM执行事务操作,写入事务日志,锁定资源,但是不会提交;TCC的从业务服务Try接口会进行业务检查,并在业务层面上锁定资源,提交事务。
- 阶段二的操作比较。2PC的在阶段一每个RM都prepare成功,那么就commit每个小事务,反之则rollback每个小事务;TCC在阶段一每个从业务服务都预留资源成功,那么confirm各个从业务服务,否则cancel所有从业务服务预留的资源。
Saga
Saga事务源于1987年普林斯顿大学的Hecto和Kenneth发表的如何处理long lived transaction(长活事务)论文,Saga事务核心思想是将长事务拆分为多个本地短事务
,由Saga事务协调器协调。
每个本地事务都有相应的执行模块和补偿模块(对应TCC中的Confirm和Cancel),当Saga事务中任意一个本地事务出错时,可以通过调用相关的补偿方法恢复之前的事务,达到事务最终一致性。
Saga模型由三部分组成:
- LLT(Long Live Transaction):由一个个本地事务组成的事务链。
- 本地事务:事务链由一个个子事务(本地事务)组成,LLT = T1+T2+T3+…+Ti。
- 补偿:每个本地事务Ti有对应的补偿Ci。
Saga的两种执行顺序:
- T1, T2, T3, …, Tn
- T1, T2, …, Ti, Ci,…, C2, C1,其中0 < i < n
Saga的两种恢复策略:
当事务链中的某一个子事务执行失败时,需要对整个分布式事务进行补偿。
-
向后恢复(Backward Recovery)
:撤销掉之前所有成功子事务。如果任意本地子事务失败,则补偿已完成的事务。如异常情况的执行顺序T1,T2,T3,…Ti,Ci,…C3,C2,C1。
-
向前恢复(Forward Recovery)
:即重试失败的事务,适用于必须要成功的场景,该情况下不需要Ci。执行顺序:T1,T2,…,Ti(失败),Ti(重试),…,Tn。
⑵ 异步通知型事务
异步通知型事务指将一系列同步的事务操作修改为基于消息队列异步执行的操作,来避免分布式事务中同步阻塞带来的数据操作性能的下降。
MQ事务消息方案
基于MQ的事务消息方案主要依靠MQ对事务的支持来实现投递消息和参与者自身本地事务的一致性。
有一些第三方的MQ是支持事务消息的,比如RocketMQ,ActiveMQ,但是也有一些常用的MQ是不支持事务消息的,比如RabbitMQ和Kafka。
MQ事务消息流程
- 消息发送者开启消息事务,向MQ发送带有事务标识的消息;
- MQ接收消息,并将消息保存到事务存储区域,但是现在不会进入队列,也就不会推送给订阅者;
- MQ通知消息发送者消息接收成功;
- 消息发送者执行本地事务,此事务一般是包含在消息事务中;
- 根据本地事务的执行结果,向MQ发送提交或者回滚指令;
- 如果是提交指令,MQ将消息持久化并进入消息队列;如果是回滚指令, MQ将丢弃该消息;
- MQ向消息订阅者推送消息;
- 消息消费者根据消息执行本地事务,或者调用第三方服务;如果消息失败,可以利用MQ的重试机制进行重试,或者消费者自己实现重试机制;可以依次提升重试的时间间隔(5min、30min、2h、12h、24h),在通知N次之后就不再通知,进行报警+记日志+人工介入;
- 消费者执行本地事务成功后,向MQ返回消费确认Ack;
- MQ将该消息标记为已消费,并按策略进行删除。
如果消息发送者在执行本地事务的过程中宕机,或者超时,MQ将询问消息发送者来获取事务状态。
如果消费者在消费时遇到业务层面的失败,则需要通知消息发送者进行事务回滚。
本地消息表方案
如果MQ不支持事务消息,则可以使用本地消息表的方案。本地消息表的方案最早由ebay提出,核心思路是将分布式事务拆分成本地事务进行处理。
本地消息表流程
- 在消息发送方的数据库中,除了业务表之外,还存在消息表,消息表记录着消息内容和消息的状态,在同一个本地事务中将业务数据和消息写入数据库。
- 发送消息到MQ。可以在本地事务完成之后紧接着进行消息投递,也可以使用专门的线程定时扫描消息表进行消息投递。
- MQ将消息推送给订阅者。
- 消息消费者进行业务处理,执行本地事务或者调用第三方服务。消息消费成功之后,通知消息发送方删除消息表中对应的记录。
在消息生产方可以有专门的工作线程定时扫描本地消息表,把需要进行处理的消息发送到MQ,这样即使消息消费者执行本地事务失败,也可以由消息发送方进行重试。如果使用这种方式,需要消费者成功之后,通知消息发送者将消息标记为已消费或者删除。
如果由消息消费者决定消息的重试机制,那么消息发送者在收到MQ消息确认Ack时,就可以将消息标记为已消费或者删除。但是仍然需要专门的工作线程扫描本地消息表,因为有可能本地事务成功,而消息发送却失败了。
消息重试也可以使用依次提升时间间隔(5min、30min、2h、12h、24h)的方式,在通知N次之后就不再通知,进行报警+记日志+人工介入。
如果消费者在消费时遇到业务层面的失败,则需要通知消息发送者进行事务回滚。
MQ事务消息与本地消息表的比较
- 相同点
- 事务消息都依赖MQ进行事务通知,都是异步的。
- 事务消息的发送方可能会重复投递消息,所以需要有相关的机制降低重复投递率。
- 事务消息的消费方需要进行幂等设计。
- 当消费者在消费时遇到业务层面失败的问题,需要提供补偿机制。
- 二者的区别
MQ事务消息方案需要MQ支持事务,业务发起方需要提供对应的本地操作成功的回查功能。DB本地消息表方案使用了数据库来存储事务消息,降低了对MQ的要求,但是增加了数据库的存储成本。