关于后端:ChatGPT万字长文理解透彻分布式事务

6次阅读

共计 16891 个字符,预计需要花费 43 分钟才能阅读完成。

分布式事务是指在分布式环境下,对多个数据资源进行并行操作时,须要保持数据资源之间的一致性和完整性,同时具备 ACID 的个性。在分布式系统中,因为存在多个数据存储节点、网络提早、可用性等问题,导致分布式事务的实现相比拟于单节点事务要更加简单和艰难。

常见的分布式事务解决方案包含

  1. 两阶段提交(Two-Phase Commit, 2PC):事务协调者(TC)首先向所有参与者(P)收回“预提交”(prepare)申请,各参与者对音讯进行确认操作。如果所有参与者都能失常执行,则协调者向参与者收回“正式提交”申请,各参与者将事务提交到本地数据库,返回确认音讯。如果该过程中呈现任何一个参与者无奈提交,则会进行回滚操作,使得全局事务回滚到最后的状态。
  2. 弥补事务(TCC):TCC 事务将一个事务以尽可能简略的模式合成为三个步骤——试着去执行它,查看是否能够提交,如果不能提交,则回滚曾经执行的动作。在 TCC 事务中,须要实现 try、confirm 和 cancel 三个接口,通过调用 confirm、cancel 接口实现提交和回滚操作。
  3. Saga 事务:Saga 是一种反对可撤销和部署在多个实例之间的长事务处理模式。Saga 事务将长事务拆分为多个小事务,每个小事务之间不再强制保障强一致性,而是通过异步音讯通信的形式进行程序化解决,从而升高了零碎的复杂度和开发成本。
  4. 音讯队列事务:在消息中间件的反对下,将音讯的生产者和消费者进行事务性单干。

以上解决方案都有其实用场景和实现细节,须要依据具体的业务需要进行抉择。同时,在利用分布式事务时还须要思考到数据一致性、可靠性、性能、可扩展性等方面的问题。

两阶段提交

两阶段提交(Two-Phase Commit,2PC)是实现分布式事务的一种较为传统的形式,它通过引入一个协调者(Coordinator)来协调多个参与者(Participant)的提交行为,从而保障分布式事务的原子性和一致性。

2PC 的过程如下所示:

阶段一:

  1. 协调者向所有分布式事务参与者发送“canCommit”申请。
  2. 各参与者接管到申请后,会相应的执行数据筹备工作。如果参与者在执行筹备工作时发现有不可解决的谬误,则向协调者发送“NO”响应。
  3. 如果所有参与者都胜利的执行了筹备工作,则向协调者发送“YES”响应。

阶段二:

  1. 如果协调者在阶段一收到了所有参与者的“YES”响应,则向所有参与者发送“doCommit”申请。参与者收到申请后执行事务提交,并向协调者返回“ACK”示意提交胜利。
  2. 如果协调者在阶段一或二的任一阶段收到了任何一个参与者的“NO”响应或超时,则向所有参与者发送“doAbort”申请,参与者执行事务回滚操作,并向协调者返回“ACK”示意回滚胜利。

2PC 的具体实现有以下几点须要留神:

  1. 参与者在接管到“canCommit”申请后,须要记录下此时的以后状态(能够提交或不可提交),以便于在回滚操作时进行信息复原。
  2. 协调者在期待参与者响应时要思考超时状况的解决。如果等待时间过长,则须要对尚未响应的参与者进行解决。
  3. 2PC 模型可能会存在“单点故障”的问题,即如果协调者呈现问题,则整个分布式事务都会进入一种无奈解决的状态。因而,须要采纳数据备份、容灾等措施来升高协调者呈现故障的概率。

总之,2PC 尽管具备原子性和一致性的特点,但其实现复杂度较高,同时存在一些可能导致性能降落和可用性升高的问题,因而须要依据具体的业务场景进行衡量和抉择。

举例说明

以转账业务为例子,介绍应用两阶段提交(2PC)实现分布式事务的过程。

假如有两个账户 A 和 B,咱们须要在分布式环境下实现从账户 A 向账户 B 转账的业务。具体过程如下:

  1. 协调者(Coordinator)向账户 A 和账户 B 的参与者(Participant)发送“canCommit”申请。
  2. 账户 A 和 B 的参与者接管到申请后进行账户余额扣减和减少操作,并记录下以后状态。如果参与者执行过程中出现异常或者产生网络故障等状况,则向协调者发送“NO”响应。
  3. 如果 A 和 B 的参与者都胜利的实现了账户余额变动操作,则向协调者发送“YES”响应。
  4. 协调者依据收到的参与者响应决定事务提交或回滚操作。

    • 如果所有参与者的响应都是“YES”,则协调者向所有参与者发送“doCommit”申请,各参与者执行提交操作并返回“ACK”示意提交胜利。
    • 如果任意一个参与者的响应为“NO”或协调者期待响应超时,则协调者向所有参与者发送“doAbort”申请,各参与者执行回滚操作并返回“ACK”示意回滚胜利。

例如,账户 A 和 B 的 Participator 胜利解决账户余额变动操作,向 Coordinator 发送了“YES”响应。协调者收到两个参与者的“YES”响应后,决定提交事务。协调者向账户 A 和 B 的 Participator 发送“doCommit”申请,各参与者收到申请后执行事务提交操作,返回“ACK”示意提交胜利。

如果账户 A 的余额有余,导致账户 A 的 Participator 向协调者发送了“NO”响应,则协调者向所有参与者发送“doAbort”申请,各参与者执行事务回滚操作,并返回“ACK”示意回滚胜利。

以上就是应用两阶段提交(2PC)实现分布式事务的过程,能够保障分布式环境下数据的一致性和完整性。

TCC

TCC(Try-Confirm-Cancel)是一种实现分布式事务的较为风行的形式,它将一个分布式事务拆解成“尝试”(Try)、“确认”(Confirm)和“撤销”(Cancel)三个阶段,从而保障了事务的原子性和一致性。

具体来说,TCC 实现分布式事务的过程如下:

  1. Try 阶段:进行第一阶段的预处理,查看所有业务参与者的执行条件,查看通过后将所有状态缓存到预提交日志中。
  2. Confirm 阶段:在第二阶段进行业务提交,如果有执行失败,则返回谬误,须要从新尝试,直到确认并执行胜利,状态提交胜利后将对应的缓存删除,开释资源。
  3. Cancel 阶段:在第二阶段,业务须要回滚,则在第三阶段进行回滚解决,勾销的同时开释被锁住的资源。

TCC 的实现须要从以下几个方面进行思考:

  1. 幂等性解决:在 Try 和 Confirm 阶段须要保障幂等性,同时须要解决反复申请的状况。
  2. 可恢复性解决:在整个分布式事务中如果出现异常或者是网络故障等非正常状况,须要通过后盾定期的恢复程序对分布式事务进行重试解决,保障分布式事务的失常提交和撤销。
  3. 长事务和非长事务:TCC 不适用于超长事务,因为在尝试期间对资源的占用可能会导致资源的不可用性。对于较短的事务,则不会受到这个问题的影响。
  4. 数据库的反对:TCC 须要对分布式数据库进行反对,或者应用相似于音讯队列的形式进行事务提交。
  5. 状态并发管制:在 TCC 模式中,预提交日志的状态会始终存在一段时间,其余构架须要在这段时间内对状态进行异步更新和读取,须要解决并发和锁的问题。

总之,TCC 是实现分布式事务的较为罕用的形式之一,绝对于 2PC 而言,它的性能和可靠性都更加优良,实现的复杂度绝对 2PC 要低。

举例说明

假如咱们有一个转账业务,须要在分布式环境下实现,应用 TCC 实现分布式事务的过程如下:

  1. Try 阶段:查看两个账户的余额是否足够,如果余额有余则不能进行转账操作,尝试锁定两个账户并预扣除转账金额,缓存此次转账记录和锁定信息到 Try 日志中。
  2. Confirm 阶段:实现转账操作,开释锁定资源。如果两个账户的余额都足够,则进行理论的转账操作,记录转账流水和对应的余额变动。如果转账操作执行胜利,则删除 Try 日志中记录的缓存。如果转账操作执行失败,则进行业务回滚,撤销 Try 日志中记录的缓存。
  3. Cancel 阶段:进行第三阶段解决,将预扣除金额返回给原账户,删除 Try 日志中记录的缓存并开释锁定的资源,确保曾经锁定的账户最终没有被转出。

例如,A 账户向 B 账户转移 1000 元,应用 TCC 实现分布式事务的过程如下:

  1. A 账户和 B 账户的参与者在 Try 阶段查看 A 账户余额足够,锁定 A 账户并预扣除 1000 元;B 账户锁定胜利。
  2. A 账户和 B 账户的参与者在 Confirm 阶段执行转账操作,记录转账流水和余额变动,开释锁定,最终确认转账操作胜利。
  3. 如果在 Try 阶段时,A 账户余额有余,则进行 Cancel 阶段解决,将预扣除的 1000 元退回到 A 账户中,开释锁定。

以上就是应用 TCC 实现分布式事务的具体过程了。TCC 通过将分布式事务拆分成“尝试”、“确认”和“撤销”三个阶段,以最小的开销保障了分布式事务的可靠性和一致性。

Saga

Saga 是一种基于弥补机制的分布式事务解决方案。它通过将整个事务拆解成一系列的部分事务,每个部分事务负责更新本人的本地状态,并通过发送 compensating action 来实现事务的撤销操作。Saga 的核心思想是以“最小承诺”缩小分布式事务的范畴,从而打消了分布式事务的复杂性,更加实用于微服务架构中的分布式场景。

应用 Saga 实现分布式事务的过程如下:

  1. 定义 Saga 事务:定义 Saga 事务中的部分事务和 compensating action。每个部分事务都会有本人的业务逻辑和状态治理,并且须要实现 compensating action 以实现事务的撤销操作,保障整个事务的可靠性。
  2. 执行 Saga 事务:Saga 事务由一个协调器进行管制,它负责调用每个部分事务,并且在每个部分事务实现后查看后果,如果任何部分事务呈现了失败,协调器将调用 compensating action 进行撤销操作。
  3. Saga 事务状态:Saga 事务的状态通过每个部分事务的执行后果进行推动,在一系列的部分事务和弥补操作中进行转移。
  4. 高可用性:Saga 事务须要保障高可用性,因而须要应用 leader 选举或主备模式来保障协调器的高可用性,以避免单点故障导致整个事务呈现失败。

举例

例如,上面是一个 Saga 事务的示例:

  1. 订单服务提交订单。
  2. 领取服务执行领取操作,如果领取失败则执行 compensating action 进行撤销操作。
  3. 发货服务执行发货操作,如果发货失败则执行 compensating action 进行撤销操作。
  4. 物流服务执行更新物流信息操作。
  5. 审核服务执行订单审核操作,如果审核失败则执行 compensating action 进行撤销操作。
  6. 订单服务发送订单确认音讯。
  7. 客户服务实现客户告诉。

在这个示例中,如果任何一个部分事务呈现失败,Saga 事务的协调器将调用 compensating action 来撤销操作,以保障整个事务的一致性和可靠性。

总之,Saga 是一种基于弥补机制的分布式事务解决方案,它提供了一种缩小事务范畴的计划,从而打消分布式事务中的复杂性,更适宜于微服务架构中的分布式场景。应用 Saga 时须要定义 Saga 事务、执行 Saga 事务、Saga 事务状态治理和保障高可用性。

音讯事务

分布式事务中的音讯事务,通常指的是在事务执行过程中所应用的音讯队列的事务。实现音讯事务的形式次要有两种,别离是本地音讯事务和分布式音讯事务。

1、本地音讯事务:

本地音讯事务是在音讯发送方和接管方所在的数据库事务中,通过音讯队列来实现数据的异步操作。在本地音讯事务中,发送方发送音讯时,将音讯插入到一个本地音讯表中,并在以后数据库事务中进行提交。如果后续在事务执行过程中须要回滚,也须要将曾经发送的音讯删除。接管方在收到音讯后,须要在本地数据库事务中进行解决。

2、分布式音讯事务:

分布式音讯事务须要音讯队列反对分布式事务的性能。常见的有基于音讯队列内嵌事务的分布式音讯事务和基于两阶段提交的分布式音讯事务。其中基于音讯队列内嵌事务的形式,比方 Kafka 中的事务反对,通过音讯队列内嵌事务来实现分布式事务的性能。在应用该形式时,音讯的发送方和接管方都须要在同一个事务中进行,如果事务呈现问题,则音讯会被回滚。

基于两阶段提交的分布式音讯事务,则将音讯队列作为一个参与者,与数据库事务一起参加分布式事务的解决。在该模式下,在分布式事务提交之前须要进行两个阶段的合作:第一阶段中,记录音讯的相干信息并将音讯发送到音讯队列;第二阶段中,音讯队列接管事务协调器发送的音讯,确认音讯能够发送,并期待最终的确认信息。如果分布式事务提交胜利,则音讯队列会将音讯发送进来;如果分布式事务回滚,则音讯队列不会发送音讯。

总的来说,实现分布式事务的音讯事务须要思考到音讯的发送、接管以及在分布式事务中的合作等方面,采纳适合的技术和计划来实现。

本地音讯事务

在实现分布式事务时,能够采纳本地事务表的模式来实现。具体实现形式如下:

  1. 在利用中定义本地事务表。能够应用 MySQL 或者其余数据库来存储本地事务表,该表中须要蕴含以下字段:
  • xid:全局惟一标识事务 ID
  • branch_id:分支事务 ID
  • status:分支事务状态(提交、回滚、未知)
  • participant_id:参与者 ID
  • create_time:分支事务创立工夫
  • update_time:分支事务更新工夫
  • rollback_info:回滚信息
  1. 在利用中应用应用 Spring Boot 集成分布式事务框架实现分布式事务,比方应用 Seata。
  2. 实现分布式事务的参与者,须要在本地事务表中记录对应的分支事务。以后节点的事务参与者须要在本地事务表中插入一条记录,示意以后节点参加了全局事务,并更新状态为“未知”。
  3. 在分布式事务提交时,须要先提交本地事务,而后依据本地事务的后果,提交或者回滚全局事务。在本地事务提交时,须要将以后节点参加的分支事务状态的状态改为“提交”,并将回滚信息置空。
  4. 如果本地事务失败,全局事务须要回滚。在回滚时,须要将参与者的分支事务状态批改为“回滚”,并将回滚信息更新到本地事务表中。这时,全局事务协调器将会回滚所有分支事务的状态。

Spring Boot 集成 Seata 能够应用 Seata 官网提供的 Spring Boot Starter,具体应用办法可参考 Seata 的官网文档。

MQ 事务

应用音讯队列(MQ)实现分布式事务,通常是采纳异步确保的形式。具体形式如下:

  1. 在分布式事务中应用音讯队列来进行数据的异步操作,同时将音讯队列作为分布式事务的参与者之一。
  2. 将音讯发送方和接管方的事务拆散开来,别离作为两个分支事务处理。在本地事务执行实现后,将要发送的音讯插入到音讯队列中,期待音讯队列将音讯发送到接管方。
  3. 当音讯发送方实现本地事务后,若事务提交胜利,则须要将音讯发送到音讯队列中,并保障音讯可靠性,保障音讯发送不会失败。如果发送失败,则须要将音讯长久化到本地数据库,并期待后续重发。
  4. 对于接管方,须要在本地事务中对接管到的音讯进行解决。如果解决胜利,则须要将音讯从音讯队列中删除,否则须要将音讯更改状态,保障音讯反复生产时的正确性。
  5. 如果在分支事务执行过程中呈现失败(比方音讯发送失败),须要对分支事务进行回滚,同时须要保障音讯队列不会将该音讯发送到接管方。在音讯队列中实现该性能,经常须要采纳阻塞式发送。

须要留神的是,应用音讯队列实现分布式事务时,因为波及到异步操作,因而须要保障音讯的可靠性,比方音讯长久化、重试机制等。同时,也须要思考到可能呈现音讯反复生产的状况,须要在音讯队列中进行判重等操作。

具体实现时,能够应用消息中间件(比方 RabbitMQ、Kafka)来实现分布式事务的音讯队列。此外,在应用分布式事务时,也能够思考分布式事务框架,比方 Seata、Hmily 等,它们能够反对分布式事务的协调、治理,提供更便捷的分布式事务实现形式。

Seata

Seata 是一种开源的分布式事务解决方案,它提供高效的多数据源、跨服务端的分布式事务管理能力。Seata 将每个事务定义为一个全局惟一的 XID(X/Open XA 规范中的标识符),通过将每个参与方的 local transaction 纳入全局事务的管理体系中,实现分布式事务的可靠性,保障多个事务操作的原子性、一致性和隔离性。

应用 Seata 实现分布式事务的过程如下:

  1. 服务端代码的革新:在所有的服务中,对于须要参加分布式事务的办法进行革新,应用 Seata 提供的 @GlobalTransactional 注解标注上事务的类型,主动开启全局事务。
  2. Seata 代理的染指:客户端须要引入 Seata 代理,Seata 代理将染指原有的分布式系统,拦挡业务申请并向 Seata Server 注册事务分支,以获取全局惟一的 XID。
  3. 分布式事务执行:开始执行分布式事务,服务中的每一个分支都会通过与 Seata 协调器的交互进行状态的更新,并在事务实现时上报状态,依据事务执行的后果告诉 Seata 进行后续的操作。
  4. Seata Server 的治理:蕴含事务的开始、弥补、提交、回滚、查问等操作,对立治理全局事务的状态。

例如,上面是应用 Seata 实现转账业务的示例:

  1. 当用户 A 向用户 B 转账时,A 服务和 B 服务须要应用 @GlobalTransactional 注解对事务进行治理。Seata 代理从两个服务中获取 XID。
  2. 而后 A 服务从 A 用户账户中扣除金额,B 服务减少金额。在扣除和减少金额过程中,Seata 将本地事务注册为分布式事务,调配分支 ID,通过异步传递分支状态并期待分支状态告诉。
  3. 如果其中一方失败,Seata 从上一个告诉的状态中检索分支,并向所有未实现工作发送事务回滚指令(暂未理论提交)。事务回滚指令胜利发送时则进行回滚(失常状态下这将是通过异步音讯来实现)。
  4. 如果所有分支工作都胜利,则 Seata 回滚底层资源管理器中记录的任何长期写入,并向所有未实现事务发送事务提交指令(失常状况下,这将通过异步音讯来实现)。

以上就是应用 Seata 实现分布式事务的过程,通过 Seata 对部分事务的承诺和向 Seata Server 的注册治理,以达到全局事务的管制和治理,实现了分布式事务的可靠性和一致性。

Seata 反对三种分布式事务模式,别离是 AT、TCC 和 SAGA,每种模式都有其实用场景,能够依据理论需要抉择应用。

1、AT 模式

AT(Alter Table)模式利用数据库提供的 ACID 事务机制,可能缩小代码的批改量,最大限度地利用已有的资源,并提供高性能和简便治理。在 AT 模式下,Seata 代理会拦挡每一个波及到数据库的 SQL 操作,当分支事务进行提交时,Seata 会主动将所有批改的数据都写入 redo log,并在回滚时将这些操作删除。AT 模式实用于业务逻辑简略,对实时性有要求的场景。

2、TCC 模式

TCC(Try Confirm Cancel)模式是一种基于业务逻辑实现的分布式事务模式。TCC 模式的原理是将一个残缺交易拆分成三个阶段——预留资源 (try)、执行操作(confirm) 和勾销操作(cancel),每个阶段对应一个事务操作,通过自定义的业务逻辑实现事务的治理。在 TCC 模式下,Seata 代理会拦挡业务申请,同时依据业务逻辑调用 try、confirm、cancel 的办法。TCC 模式实用于业务逻辑简单,须要定制化事务管理和数据处理的场景。

3、SAGA 模式

SAGA(Saga pattern)模式是一种基于弥补机制的分布式事务模式。相比于 AT 和 TCC 模式,SAGA 模式更加实用于零碎与零碎之间的分布式事务场景。SAGA 模式将简单的分布式事务拆分成一个个小的本地事务和弥补操作,并通过弥补操作保障整个事务的一致性。在 SAGA 模式下,Seata 会依据应用程序的 Saga 定义动静地创立和治理 micro transactions,从而实现不同服务之间的交互和事务的解决。SAGA 模式实用于不同服务之间存在多阶段业务流程,须要依据业务逻辑实现事务管理的场景。

总之,Seata 反对三种分布式事务模式,每种模式都适宜不同的利用场景和业务需要。在利用中抉择适合的事务模式十分重要,能够依据具体业务需要抉择 AT、TCC 和 SAGA 中的一种或几种来实现分布式事务。

AT

在 Spring Boot 中应用 Seata 的 AT 模式,大略须要以下步骤:

  1. 引入相干依赖
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.4.2</version>
</dependency>
  1. 配置文件批改

在 application.yml 或 application.properties 中增加以下 Seata 配置项:

spring:
  application:
    name: xxx-service   # 这里是你的服务名,须要与 Seata Server 上的注册信息对应
  cloud:
    alibaba:
      seata:
        tx-service-group: my_test_tx_group   # 这里指定 Seata 服务的事务组名
        service:
          vgroup:
            my_test_tx_group: "default"   # 这里指定 Seata Server 默认的事务组名
          group:
            my_test_tx_group:   # 把这个服务注册到 Seata Server 的事务组名
              default:
                annotation-interceptor-order: 1
                undo-data-validation: true
                mode: AT  # 这里指定 AT 模式
                log-store: db
                lock:
                  type: DB
                  # 记得把上面的 DB 配置改成你的数据库配置
                  db:
                    datasource: druid   # javax.sql.DataSource 类型,倡议应用集成连接池,例如 druid、hikari 等
                    ...
                report-retry-count: 5
  1. 补充 Seata 配置文件

在 Seata Server 的 registry.conffile.conf 文件中,须要退出对本服务的配置:

[registry]
# example: file:/registry
type: file
nacos:
  serverAddr: localhost:8848
  namespace: please_set_your_namespace
  cluster: default

client:
  ...
  customizedRegistryClassName: io.seata.registry.FileRegistry
  applicationId: my_test_tx_group
  txServiceGroup: my_test_tx_group
  env: test

# file registry config
file:
  name: file.conf

[registry-file]
type: file

serverList: file://registry

[service]
vgroupMapping.my_test_tx_group=default
default.grouplist=file://127.0.0.1:8091
enableDegrade=false
disableGlobalTransaction=false
  1. 让业务办法反对 Seata 的分布式事务

在须要应用 Seata 的分布式事务的办法上加上 @GlobalTransactional 注解,则此办法即变成了全局事务,如下所示:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    OrderDAO orderDAO;

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    @Override
    public Integer createOrder(OrderDTO orderDTO) {// 业务逻辑}
}

其中,@GlobalTransactional 注解的 name 属性标注此次全局事务的名称,rollbackFor 属性标注回滚的异样类型。

最初,配置好之后运行服务,如果一切正常,你就能够在 Seata Server 的事务列表中看到你的服务退出了一个新的分布式事务了。

通过以上步骤,咱们就能够在 Spring Boot 利用中应用 Seata 的 AT 模式实现分布式事务管理。

TCC

在 Spring Boot 中应用 Seata 的 TCC 模式,大略须要以下步骤:

  1. 引入相干依赖
<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-spring-boot-starter</artifactId>
  <version>1.4.2</version>
</dependency>
  1. 配置文件批改

在 application.yml 或 application.properties 中增加以下 Seata 配置项:

spring:
  application:
    name: xxx-service   # 这里是你的服务名,须要与 Seata Server 上的注册信息对应
  cloud:
    alibaba:
      seata:
        tx-service-group: my_test_tx_group   # 这里指定 Seata 服务的事务组名
        service:
          vgroup:
            my_test_tx_group: "default"   # 这里指定 Seata Server 默认的事务组名
          group:
            my_test_tx_group:   # 把这个服务注册到 Seata Server 的事务组名
              default:
                annotation-interceptor-order: 1
                undo-data-validation: true
                mode: TCC  # 这里指定 TCC 模式
                log-store: none
                lock:
                  type: db   # TCC 模式锁的类型须要设为 db
                  db:
                    ...
                report-retry-count: 5
  1. 补充 Seata 配置文件

在 Seata Server 的 registry.conffile.conf 文件中,须要退出对本服务的配置:

[registry]
# example: file:/registry
type: file
nacos:
  serverAddr: localhost:8848
  namespace: please_set_your_namespace
  cluster: default

client:
  ...
  customizedRegistryClassName: io.seata.registry.FileRegistry
  applicationId: my_test_tx_group
  txServiceGroup: my_test_tx_group
  env: test

# file registry config
file:
  name: file.conf

[registry-file]
type: file

serverList: file://registry

[service]
vgroupMapping.my_test_tx_group=default
default.grouplist=file://127.0.0.1:8091
enableDegrade=false
disableGlobalTransaction=false
  1. 让业务办法反对 Seata 的分布式事务

在须要应用 Seata 的分布式事务的办法上加上 @TccTransaction 注解,接着实现该办法对应的三个办法(try、confirm、cancel),同时这三个办法须要应用 @Compensable 注解,如下所示:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    OrderDAO orderDAO;

    @TccTransaction(confirmMethod = "confirmCreateOrder", cancelMethod = "cancelCreateOrder")
    @Override
    public boolean createOrder(OrderDTO orderDTO) {
        // TCC try 办法,不须要做什么
        return true;
    }

    @Compensable(confirmMethod = "confirmCreateOrder", cancelMethod = "cancelCreateOrder")
    public void tryCreateOrder(OrderDTO orderDTO) {
        // TCC try 办法,预留资源
        orderDAO.insert(orderDTO);
    }

    @Compensable(confirmMethod = "confirmCreateOrder", cancelMethod = "cancelCreateOrder")
    public void confirmCreateOrder(OrderDTO orderDTO) {// TCC confirm 办法,提交分布式事务}

    @Compensable(confirmMethod = "confirmCreateOrder", cancelMethod = "cancelCreateOrder")
    public void cancelCreateOrder(OrderDTO orderDTO) {
        // TCC cancel 办法,回滚分布式事务
        orderDAO.delete(orderDTO.getId());
    }
}

其中,@TccTransaction 注解在办法级别上表明以后办法须要反对分布式事务,同时指定了 try 办法对应的 confirm 办法和 cancel 办法。

而 @Compensable 注解则在子办法级别上标注了以后办法须要纳入分布式事务的治理,同时指定了该办法在 confirm 和 cancel 时须要执行的办法。

最初,配置好之后运行服务,如果一切正常,你就能够在 Seata Server 的事务列表中看到你的服务退出了一个新的分布式事务了。

通过以上步骤,咱们就能够在 Spring Boot 利用中应用 Seata 的 TCC 模式实现分布式事务管理。

Saga

在 Spring Boot 中应用 Seata 的 Saga 模式,须要以下步骤:

1、引入相干依赖

<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-spring-boot-starter</artifactId>
  <version>1.4.2</version>
</dependency>

2、配置文件批改

在 application.yml 或 application.properties 中增加以下 Seata 配置项:

# Seata 配置
spring:
  application:
    name: xxx-service # 这里是你的服务名,须要与 Seata Server 上的注册信息对应
  cloud:
    alibaba:
      seata:
        tx-service-group: my_test_tx_group # 这里指定 Seata 服务的事务组名,须要与 Seata Server 上的设置统一
        service:
          vgroup:
            my_test_tx_group: "default" # 这里指定 Seata Server 默认的事务组名
          group:
            my_test_tx_group: # 把这个服务注册到 Seata Server 上的事务组名
              default:
                mode: SAGA # 指定 saga 模式
                health-check: false
                report-retry-count: 5
                max-commit-retry-timeout: 300
                max-rollback-retry-timeout: 30

3、配置 Seata Server 的 endpoint

在 Seata Server 的配置文件 registry.conf 中,须要为每个要退出 Saga 模式的服务,配置其 endpoint。这里以两个服务为例:

[registry]
# example: file:/registry
type: file
nacos:
  serverAddr: localhost:8848
  namespace: please_set_your_namespace
  cluster: default

client:
  ...
  customizedRegistryClassName: io.seata.registry.FileRegistry
  applicationId: my_test_tx_group
  txServiceGroup: my_test_tx_group
  env: test

# file registry config
file:
  name: file.conf

[registry-file]
type: file

serverList: file://registry

[service]
vgroupMapping.my_test_tx_group=default
default.grouplist=file://127.0.0.1:8091,file://127.0.0.1:8092
enableDegrade=false
disableGlobalTransaction=false

[saga]
store.mode=db  # saga 模式须要指定 store.mode 为 db
store.db.driver-class-name=com.mysql.cj.jdbc.Driver   # 应用 MySQL 数据库存储 Saga 状态
store.db.url=jdbc:mysql://localhost:3306/seata_saga?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
store.db.username=root
store.db.password=123456                                    
store.db.min-conn=5
store.db.max-conn=30
store.db.global-table-name=seata_global_table   # 全局事务表名,默认值为 global_table
store.db.branch-table-name=seata_branch_table   # 分支事务表名,默认值为 branch_table
store.file.path=/seata/saga  # 应用文件存储 Saga 状态

其中,store.mode 须要指定为 dbstore.db 指定数据库相干信息。

4、编写 Saga 并增加 @SagaTransactional 注解

在须要实现 Saga 模式的业务操作方法上增加 @SagaTransactional 注解,并编写与之对应的 Saga 对象及其步骤执行逻辑。

上面是一个示例:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDAO orderDAO;

    /**
     * 创立订单
     */
    @SagaTransactional
    @Override
    public void createOrder(OrderDTO orderDTO) {
        // 扣减商品库存
        ProductReduceStockDTO productReduceStockDTO = new ProductReduceStockDTO(orderDTO.getProductId(), orderDTO.getAmount());
        productClient.reduceStock(productReduceStockDTO);

        // 下单
        orderDAO.insert(orderDTO);

        // 发送领取事务
        SagaRequest sagaRequest = new SagaRequest();
        sagaRequest.setServiceName("account-service");
        sagaRequest.setMethodName("pay");
        sagaRequest.setPayloads(new Object[]{orderDTO.getUserId(), orderDTO.getTotalAmount()});

        SagaDefinition<OrderDTO> sagaDefinition = new SagaDefinition<>();
        sagaDefinition.setSagaName("create-order-saga");
        sagaDefinition.setPayload(orderDTO);
        sagaDefinition.setSteps(Arrays.asList(new SagaStep<>("product-service", "reduceStock", productReduceStockDTO),
                new SagaStep<>("order-service", "insert", orderDTO),
                new SagaStep<>(sagaRequest)
        ));

        SagaContext start = SagaContext.start();
        SagaManager.executeSaga(sagaDefinition, start);
    }

    @CompensableConfirm
    public void createOrderConfirm(OrderDTO orderDTO) {// do nothing}

    @CompensableCancel
    public void createOrderCancel(OrderDTO orderDTO) {orderDAO.delete(orderDTO.getId());
    }
}

其中,@SagaTransactional 注解在办法上示意这是一个 Saga 分布式事务操作。

SagaDefinition 示意一个 Saga 分布式事务的定义,蕴含了该 Saga 的名称、开始时的 payload(启动该 Saga 执行的参数)、以及一系列的步骤,每个步骤都是一个 SagaStep 对象。

@CompensableConfirm@CompensableCancel 注解别离示意执行确认和勾销操作。这些办法的实现该当和原始操作相同,以确保分布式事务的完整性。

5、运行服务

配置好 Seata Server 和相干配置信息之后,就能够启动利用并运行测试了。如果一切正常,你就能够在 Seata Server 的 Saga 实例中看到对应的实例,并能够查看各个步骤的执行后果。

通过以上步骤,咱们就能够在 Spring Boot 利用中应用 Seata 的 Saga 模式实现分布式事务管理。

须要留神哪些方面

在实现分布式事务时,须要留神以下几个方面:

  1. 数据库的一致性:分布式事务波及到多个数据库,须要确保各个数据库操作的一致性。这能够通过在事务开始时对数据库进行锁定,保障在这个事务完结前其余事务无法访问受锁定的数据,从而保障了数据的一致性。
  2. 事务的可靠性:分布式事务须要确保事务的可靠性,即在各个节点产生故障或者网络谬误时,可能保障事务的正确执行。这能够通过应用分布式事务协定或者保障事务的幂等性来实现。
  3. 事务的性能:分布式事务绝对于本地事务,会带来一些额定的性能开销。因而,在实现分布式事务时须要思考性能问题。例如能够通过分片、异步操作等形式来优化性能。
  4. 基础设施的反对:分布式事务须要底层基础设施的反对,例如分布式锁、音讯队列、分布式计算等。因而,在实现分布式事务时须要思考基础设施的反对,并抉择适合的技术栈。
  5. 代码的可维护性:分布式事务波及到多个节点的操作,因而代码的可维护性十分重要。在实现分布式事务时须要思考代码的可维护性,例如能够通过模块化、对立接口等形式来进步代码的可维护性。

面试常问

以下是一些对于分布式事务的常见面试考点:

  1. 什么是分布式事务?

分布式事务是指逾越多个计算机或者零碎的一种事务,并且在多个数据库、文件系统或其余系统资源上逾越多个事务管理器或协调器。分布式事务须要保证数据在分布式环境下的一致性。

  1. 分布式事务的实现形式有哪些?

分布式事务的实现形式有以下几种形式:

  • 2PC (Two-Phase Commit):通过协调者来治理事务的提交和回滚,实现多个数据库、过程之间的一致性。
  • 3PC (Three-Phase Commit):2PC 的改进版,解决了 2PC 中的阻塞问题。
  • TCC (Try-Confirm-Cancel):在分布式环境中,将一个分布式事务拆分成多个本地事务,容许服务自行处理事务的确认或勾销。
  • Saga:将一个分布式事务拆分成多个子事务,每个子事务都有本人的本地事务管理器来解决本人的事务状态,在子事务之间传递音讯来保障最终一致性。
  • 本地音讯表:用于处理事务间的关系,通过本地音讯表保护各个事务的状态,在事务提交时才向内部零碎收回音讯。
  1. 什么是 2PC?

2PC (Two-Phase Commit) 是一种分布式事务的实现形式。在 2PC 中,协调者将会在两个阶段来提交事务:prepare 和 commit。在 prepare 阶段,协调者会向所有参与者告诉分布式事务的筹备状态,并要求各个参与者在本地筹备好事务。在 commit 阶段,如果所有参与者在 prepare 阶段都反馈了已筹备好事务的状态,协调者会告诉所有参与者提交事务,否则协调者会申请所有参与者回滚事务。

  1. 2PC 的长处和毛病是什么?

2PC 的长处是:

  • 反对强一致性,所有节点的状态雷同。
  • 协调者负责整个事务的治理,绝对简略。
  • 标准化实现,易于开发调试。

2PC 的毛病是:

  • 阻塞性问题,要期待所有参与者反馈后果后能力实现事务。
  • 单点故障,协调者呈现问题会导致整个事务无奈持续进行。
  • 吞吐量和可扩展性存在瓶颈,因为协调者负责整个事务的解决,因而无奈扩大申请的吞吐量。
  1. 可靠消息最终一致性框架的实现形式有哪些?

可靠消息最终一致性框架的实现形式有以下几种形式:

  • TCC:Try-Confirm-Cancel 的缩写。尝试先执行须要近程执行的事务;如果胜利,则进行执行确认,否则则进行执行勾销,从而实现事务的回滚操作。
  • Saga:将一个分布式事务拆分成多个子事务,每个子事务都有本人的本地事务管理器来解决本人的事务状态,在子事务之间传递音讯来保障最终一致性。
  • 本地音讯表:用于处理事务间的关系,通过本地音讯表保护各个事务的状态,在事务提交时才向内部零碎收回音讯。

本文由 mdnice 多平台公布

正文完
 0