likes
comments
collection
share

分布式事务

作者站长头像
站长
· 阅读数 11

1、分布式事务的由来

1.1、什么是事务?

事务(Transaction)通常的定义是:作为单个逻辑单元执行的一组操作,要么全部执行,要么全部不执行。它有四个明显的特征:原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability),简称ACID。结合一个简单的例子进行说明:一次用户的操作,涉及到多个不同数据表的数据变更,想要在一次操作内实现要么全部变更完成返回成功,要么全部不变更直接返回失败,如果执行到中途失败了需要将已执行的变更进行撤回,这就是一次典型的事务

分布式事务(Distributed Transaction)最早指的就是涉及多个资源的数据库事务,不过近年来随着SOA、微服务等概念的流行,分布式事务概念也有所泛化,根据上下文的不同分为系统事务(System Transaction)和业务事务(Business Transaction),前者多指数据库事务,而后者多指业务交易,需要关注的是如何保证交易的整体原子性和一致性,特点是时间跨度很长,比如餐厅线上预订,可能从用户点击预定到商户实际确认要一两天才能完成。不过无论哪一种事务,因为事务的持久性特征导致事务实现最终都需要依赖存储介质,因此在谈到事务时很难脱离数据库。

分布式事务

1.1.1、单机事务

在讲解分布式事务前,我们先来回顾一下单机事务主要有哪些特性:

  • 原子性:原子性是指事务的操作都是原子的,操作要么全部成功,要么失败全部回滚;
  • 一致性:一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态;
  • 隔离性:隔离性是指事务的操作之间是相互隔离的,互不干扰,多个事务并发执行时,就感觉像单一事务执行一样,达到预期结果;
  • 持久性:持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作;

以上的事务特性,在业务上我们都是依赖数据库去实现的。单机事务能够保证以上特性,其实说的直接一些就是,目前我们业务系统实现的所有事务操作,都是依赖于数据库实现的。而数据库如何实现事务的,以及如何保证以上的四个特性不是本文的重点,感兴趣的同学可以自行研究数据库事务。

单机事务处理流程如下图描述:

分布式事务

1.1.2、分布式事务

在业务进行拆分后,一个业务上的原子操作可能由多个分布在不同的业务系统共同完成,那么就将原来的一个单机的数据库事务,间接的变成了由多个数据库事务协作完成,故而就引入了分布式事务问题。又特别是在现在微服务大行其道的情况下,很多互联网公司都在做业务拆分,做服务化,那么随之而来的必然就是分布式事务问题,目前做服务化后,分布式事务就成了公司的痛点,成为了微服务落地的最大障碍,也是最具挑战的技术难题,解决方案也是百花齐放,各不相同,为此,本文将深入探讨微服务架构下的分布式事务解决方案。分布式事务简单描述如下:

分布式事务

1.2、为什么会产生分布式事务?

产生分布式事务的原因大致可以分为两类,下面分别进行介绍。

1.2.1、服务的多节点

在SOA、微服务场景下,许多一开始大而全的服务都会业务领域进行拆分,这往往会导致原本在一个服务内就可以闭环完成的简单操作变成需要多个不同服务协作完成的复杂操作,而不同服务往往又会对应不同的数据资源,此场景下如果对操作有事务要求自然就产生了分布式事务的问题。

分布式事务 如上图,一个应用被拆分为了服务A(RemoteServiceA)、服务B(RemoteServiceB)、服务C(RemoteServiceB),分别对应了数据库A、数据库B、数据库C。如下示例,如果服务B某个方法(updateAll)既需要更新本地数据还需要通过调用服务A和服务B提供的服务更新各自数据库数据时,方法如何保证事务性就成了一个分布式事务问题,我们没法简单的通过配置常用的事务管理器管理这种场景下的整体事务,因为传统的事务管理器控制域都是作用在本地的,不支持跨服务传递。

// 服务B
public class RemoteServiceB {
    
  public void updateAll() {
    // 更新本地数据库B的数据
      this.updateSthInDatabaseB();
    // 调用远程服务A的方法,更新数据库A的数据
      remoteServiceA.updateSthInDatabaseA();
    // 调用远程服务C的方法,更新数据库C的数据
      remoteServiceB.updateSthInDatabaseC();
  }
  
  private void updateSthInDatabaseA() {
  }
}

1.2.2、资源的多节点

当业务规模发展到一定程度,除了从业务领域角度进行纵向拆分外,往往还会考虑到数据的水平拆分,会把一些量大且重要的库按水平进行分表,而考虑到容灾和性能问题,还会进行分库分集群,这会导致原本在单个数据库内的简单数据操作变成了涉及多个数据库的跨库操作,此场景下如果对操作有事务要求自然就产生了分布式事务的问题。

分布式事务

如上图,一个服务(LocalService)对应数据被分散存储到三个不同数据库A、数据库B、数据库C。如下示例,如果服务中某个方法(updateAll)既需要同时更新三个数据库的数据时,方法如何保证事务性就成了一个分布式事务问题,我们没法简单的通过配置常用的事务管理器管理这种场景下的整体事务,因为常用的事务管理器控制域都是作用在本地的,不支持跨数据库传递。

// 服务B
public class LocalService {
  public void updateAll() {
    // 更新数据库A的数据
      this.updateSthInDatabaseA();
    // 更新数据库B的数据
      this.updateSthInDatabaseB();
    // 更新数据库C的数据
      this.updateSthInDatabaseC();
  }
  
  private void updateSthInDatabaseA() {
    // 执行sql
  }
  private void updateSthInDatabaseB() {
    // 执行sql
  }
  private void updateSthInDatabaseC() {
    // 执行sql
  }
}

1.3、有哪些理论和问题?

1.3.1 CAP理论

一般来说分布式系统都脱离不开CAP理论,该理论认为一个分布式系统中, 一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance),三者不可得兼。因此在设计分布式系统时,就存在一定的取舍,那么在解决分布式事务时,如果完全强调事务的ACID特征,按照理论就必然需要牺牲系统的可用性,但是可用性又是现在大型分布式系统的核心关注指标,这种矛盾就是分布式事目前面临的首要问题

1、一致性 (C:Consistency)

在分布式系统下,为了保证系统的高可用,数据是需要进行多分拷贝做数据备份(或者为了保证数据的数据的读写分离,同一数据需要分布在不同的系统中)。数据一致性是指在多个副本之间(或多份数据之间)是否能够保持一致性。在一致性的需求下,当一个系统在数据一致的情况下执行的更改操作后,应该保证系统的数据仍然处于一致的状态。

对于一个将副本数据分布在分布式不同节点上的系统来说,如果第一个节点对节点进行了更新,第二个节点缺没有完成更新操作,那么在第二个节点上的数据与第一个节点的数据就不一致,就可能导致在第二个节点上读取的数据不正确,这就是比较典型的分布式系统下数据不一致的场景。

2、可用性(A:Availability)

在分布式环境下,可用性是指系统提供的服务一直处于可用的状态,对于任何用户的请求,总是能够在一定的时间内做出响应,返回结果。这里需要重点说明“一定时间”与“返回结果”。

“一定时间”是指,对于用户的请求操作,系统必须能够快速响应结果,如果处理时间超出一定的范围,调用方可能自行断开连接,标识为服务不可用或服务响应变慢,导致业务受到影响,接口的性能指标是能不比较直观的反应在tp99耗时,QPS/TPS

“返回结果”是系统的可用性的重要指标,它要求系统在完成对用的请求处理后,能够按照接口定义,响应正确的结果。所有的影响结果能够明确地反应出对请求的处理结果,不管是成功或失败,都能够明确表示。

3、分区容错性 (P:Partition tolerance)

由于分布式系统是通过网络进行通信,网络是不可靠的,当出现任意的网络分区出现故障的时候,任然能够保证服务对外提供一致性和可用性的服务。换句话说,分区容错是站在分布式系统的角度,对访问本系统的调用方的一种承诺。只要不出现整个网络环境的不可用,分布式系统都能保证提供服务。

分布式事务

1.3.2 Base理论

BASE理论是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。BASE理论是对CAP理论中的一致性和可用性权衡的结果,通过对互联网系统分布式实践的总结,其核心思想是在分布式系统中,即使无法做到强一致,但每个服务可以结合自身的业务特点,采用适合自己的方式使系统达到最终一致性。BASE理论中的三要素描述如下:

1、基本可用

基本可用是指分布式系统在出现故障后,允许部分可用性损失,即是保证核心服务或链路是可用的。

比如:电商大促,当出现访问量陡增,为了保证系统的可用性,部分商户可能被引导到降级页面,保证大部分商家的一个可用性。

2、软状态

软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体。比如电商网站上看到的商品剩余数量,评论数据,点赞数等;

3、最终一致性

最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

总的来说,BASE理论面向的是大型高可用可扩展的分布式系统,和传统的事物 ACID 特性是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但是在分布式系统的场景中,不同的业务单元对数据的一致性要求是不同的,因此在架构设计中,ACID与BASE理论往往是结合一起考虑的。

分布式事务

2、常见解决方案

你需要先了解这些概念

名词概念
事务管理器(Transaction Manager)事务管理器是一个独立的服务,用于控制分布式事务的生命周期,包括创建主事务记录、分支事务记录,并根据分布式事务的状态,调用参与者提交或回滚方法。
资源管理器(Resource Manager)任意类型的持久化数据存储,如常见的关系型数据库甚至消息队列。通常情况下,我们因为不直接操作存储资源,所以可以理解为数据源适配器。
事务协调器(Transaction Coordinator)事务协调器是一个独立的模块,用来控制事务的提交和回滚操作。事务协调器可嵌入在客户端中独立运行,也可部署在Server端作为独立服务。
全局事务(Global Transaction)全局事务是一个逻辑上的概念,他并不是具体执行的某段逻辑。一个全局事务包含了多个具体的分支事务,发起方通过修改全局事务的状态,控制分支事物的提交/回滚。
分支事务(Branch Transaction)分支事务是一个逻辑上的概念,一个分布式事务可能包含多个数据库本地事务,在分布式事务框架下,分支事务可能是一个分库上执行的 SQL 语句,或是一个自定义模式服务的调用。
事务发起方(Launcher)分布式事务的发起方负责启动分布式事务,通过调用参与者的服务,将参与者纳入到分布式事务当中,并决定整个分布式事务是提交还是回滚。一个分布式事务有且只能有一个发起方。
事务参与方(Participant)参与者提供分支事务服务。当一个参与者被发起方调用,则被纳入到该发起方启动的分布式事务中,成为该分布式事务的一个分支事务。一个分布式事务可以有多个参与者。

2.1、X/Open XA协议

XA是一个分布式事务协议,由Tuxedo提出。XA规范主要定义了(全局)事务管理器(Transaction Manager)和(局部)资源管理器(Resource Manager)之间的接口。XA接口是双向的系统接口,在事务管理器Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁。

分布式事务

XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。

2.2、两阶段提交

两阶段提交(Two-Phase Commit,以下简称2PC)方案,是指,为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法(Algorithm)。通常,二阶段提交也被称为是一种协议(Protocol)。在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。

  • 一阶段——准备阶段(Prepare Phase):事务发起方通过事务管理器发起一个分布式事务后,由事务协调器(事务管理器)通知各个事务参与方(资源管理器),给他们发送一条prepare指令,每个参与者要么返回失败,要么就进行执行本地事务(分支事务),写本地redo和undo日志,但是不进行事务的commit,到达一种临界状态,此时每个参与者持有当前本地事务涉及的锁资源不释放;
  • 二阶段——提交阶段(Commit Phase):事务协调器收集所有事务参与方在一阶段返回的信息,如果都成功则通知所有参与方进行事务提交(Commit),如果有返回失败或超时,则通知所有参与方进行事务回滚(Rollback)。参与方根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。

如下图是2PC方案的简单流程示意图,不难发现事务管理器直接与资源管理器进行交互,中间不需要业务逻辑的介入

分布式事务

事务管理器:负责发起和协调整个分布式事务,推进分布式事务流程,保证分布式达系统到一致的状态;

资源管理器:负责预留资源,提供提交或取消操作,协助事务管理器完成一致性保证;

2.2.1、优点

  • 数据库层面(资源管理器)层面控制分布式事务,业务层面无感知或低侵入
  • 强一致性

2.2.2、缺陷

  • 同步阻塞:如上图,整个执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
  • 单点故障:由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
  • 数据不一致:在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
  • 二阶段无法解决的问题:协调者发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

2.2.3、3PC:三阶段提交协议

为了解决二阶段协议中的同步阻塞等问题,三阶段提交协议在协调者和参与者中都引入了超时机制,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。

三阶段中的 Three Phase 分别为 CanCommit、PreCommit、DoCommit 阶段。

分布式事务

在提交阶段如果发送的是中断事务请求,但是由于网络问题,导致部分参与者没有接到请求,那么参与者会在等待超时之后执行提交事务操作,这样这些由于网络问题导致提交事务的参与者的数据就与接受到中断事务请求的参与者存在数据不一致的问题。 所以无论是2PC还是3PC都不能保证分布式系统中的数据100%一致。

2.2.4、TXC框架

TXC全称是(Tabao Transaction Constructor),由阿里2014年启动的项目,以满足应用程序架构从单一服务变为微服务所导致的分布式事务问题,2016年更名为GTS,2019年阿里开源了其分布式事务产品Seata,TXC在其中被当做一种支持模式为用户提供分布式事务能力,简称AT模式。在TXC中,开发只需要关注业务逻辑的实现,而不需要关注分布式场景下的事务保证,TXC会通过框架代理的方式完成事务的注册、提交、回滚等操作,具有代码无侵入,接入简单,适用场景广泛等优点

TXC其实是2PC方案的应用层实现,因此仍然保留了2PC的一阶段准备和二阶段提交的思想,不同点在于将数据库层面的实现放到应用层框架中实现,原理是在应用层实现了SQL解析并自动补偿,在TXC中,分布式事务的执行流程如下图左边所示:

  1. 发起方通过事务管理器开启分布式事务(所以事务参与方通过各自的资源管理器向事务协调器注册全局事务记录);
  2. 执行业务流程,各个事务参与方执行各自的分支事务(资源管理器想事务协调器上报状态);
  3. 发起方通过事务管理器结束分布式事务,事务一阶段结束(事务管理器通知事务协调器提交/回滚分布式事务);
  4. 事务协调器汇总事务信息,决定分布式事务是提交还是回滚;
  5. 事务协调器通知所有事务参与方进行提交或回滚,事务二阶段结束;

如下图左边所示,使用数据库XA支持分布式事务和使用TXC框架支持分布式事务,都不会对业务造成侵入,不同点在于:

  • XA在数据库层面进行了分布式事务的支持
  • TXC在应用层面通过代理SQL的方式进行了分布式事务的支持

分布式事务

2.3、TCC

Try-Confirm-Cancel(以下简称TCC)方案,和严格遵守ACID的2PC方案不同,主要实现的是最终一致性,且主要面向业务层面的事务控制,通过对业务逻辑(业务系统自己实现)的调度来实现分布式事务,整个方案有三段业务逻辑,分别为尝试操作(Try)、确认操作(Confirm)、取消操作(Cancel),按执行步骤分为两个阶段:

  • 一阶段——尝试操作(Try):事务发起方在业务代码中,显示的对所有参与事务的参与方提供的Try操作,进行业务逻辑前的业务检查(一致性),完成业务资源的预留和锁定(准隔离性);
  • 二阶段——确认操作(Confirm):如果一阶段执行成功,不做业务检查,执行业务逻辑,使用Try阶段预留的业务资源;
  • 二阶段——取消操作(Cancel):如果流程中执行失败,执行补偿逻辑,对Try阶段预留的业务资源进行释放;

还有一种常见的变种方案,方案中有两段业务逻辑,分别为执行操作(Do)和补偿操作(Compensate),按执行步骤同样分为两个阶段:

  • 一阶段——执行操作(Do):直接执行业务校验和业务逻辑,并对结果持久化,业务操作结果外部可见;
  • 二阶段——补偿操作(Compensate):逆向逻辑,一阶段操作失败后的抵消和补偿,如果一阶段成功则不需要执行二阶段;

两种方案的区别在于业务逻辑的粒度,Do操作相当于Try + Confirm,如果Try出现失败的情况很多则建议使用标准的TCC实现,如果Try很少出现失败则可以使用变种方案

如下图是TCC方案的简单流程示意图,可以发现事务参与方的Try方法是有发起方在业务代码中进行调用的,而事务参与方的Confirm和Cancel方法的调用则是由事务协调器来调用的。

分布式事务

和2PC最大的区别就是RM的位置移到了业务层

第一阶段(try阶段):检查资源,预留资源

第二阶段(confirm、cancel阶段):确认或消息

2.3.1、优点

  • 保证隔离性
  • 方案灵活,基本能覆盖所有业务场景,可操作性强
  • 整体可用性高

2.3.2、缺陷

  • 成本高,如上图不难发现所有事务参与方都需要实现Try、Confirm、Cancel三个逻辑上的方法
  • 代码侵入高,原因同上

2.3.3 Swan TCC 本地模式接入(美团框架)

本地TCC主要指的是TCC框架的一种轻量化实现,公司的Swan框架、开源的EasyTransaction、ByteTCC等对其均有实现,其主要思想是事务的协调不再依赖远端 TC 集群,而是将 TC 的功能内嵌到客户端 SDK 中,随着业务机器部署,整个系统不存在单点风险,没有网络延时隐患,更加轻量级,可用性只依赖业务数据库的可用性。但是 LocalTCC 模式只能协调一层 TCC 事务,无法支持层级调用,适合于追求高性能和轻量化的用户使用。另外事务的二阶段的 Confirm(Cancel)也由事务发起方在代码里进行同步调用,不再通过 TC 进行控制。本地模式和远端模式的适用场景并不相同,可以互为补充,好处是涉及到跨端调用时不需要外部方进行项目改造,只需要事务发起方自己进行改造即可。

如下图左边所示,我们可以发现原来经典TCC方案中各个事务参与方都需要实现的Try、Confirm、Cancel操作已经不再需要,转而由事务发起方来实现,事务发起方在实现的Try、Confirm、Cancel方法内显示调用事务参与方对应的业务校验、业务执行、业务撤销等业务方法,完成业务逻辑上的分布式事务控制。

分布式事务

2.4、Saga

Saga是一种常见的处理长活事务(Long Lived Transaction)的方案,其核心思想是通过将一个跨服务跨数据库的业务流程(全局事务),分解为一些列可以保证事务性的业务动作(分支事务)集合(这种思想有点类似于分治思想),每个业务动作(Do)都是可以保持ACID特性的真实事务,且都需要提供相应的补偿操作(Compensate),按照一定顺序去执行这些动作,如果所有动作都执行成功则认为整体业务流程完成(事务提交),如果中间发生异常情况则需要通过补偿操作进行补偿。在Saga中,按照执行顺序分为两种流程:

  • 正向业务流程:按照一定顺序依次执行所有的业务动作(Do),每个业务动作都在执行完立即提交;
  • 逆向补偿流程:如果业务流程执行出现异常,则通过补偿操作(Compensate),按照业务流程的反向,依次撤销和补偿已经执行过的业务操作;

如下图是Saga方案的简单流程示意图,绿色即为正向流程,橙色是反向流程。

分布式事务

2.4.1、优点

  • 适合长流程状态驱动的场景
  • 方案灵活

2.4.2、缺陷

  • 隔离性差,如图所示一旦事务A执行完即提交,此时整个全局事务未完成时,外部已经可以获取事务A提交的数据,容易造成脏读
  • 还原度差,因为隔离性差,所以一旦需要走逆向补偿流程时,完全还原到提交前的状态在高并发时基本不太可能

2.5、可靠消息

对于常见的微服务系统,系统间的调用大部分场景都是通过RPC或HTTP进行同步调用,此时通过上面提到的2PC、TCC、Saga等方案来实现分布式事务是较为合适的,但是如果系统间不直接依赖,而是通过MQ等方式进行异步交互时,应该如何实现分布式事务呢?这个时候,就要可靠消息方案来解决了。

可靠消息方案主要指的是在业务互动的主动方与被通知方之间,架设一个稳定可靠的消息系统来保证业务活动主动方执行本地业务动作与通知具备事务性,也就是说如果业务活动的主动方事务执行成功,被动方一定能收到相应的业务通知,反之如果主动方的事务回滚则业务通知不会发送给被动方。

整个方案分步骤:(阿里 RocketMQ实现MQ异步确保型事务)

  1. 事务发起方首先发送半消息到MQ;
  2. MQ通知发送方消息发送成功;
  3. 在发送半消息成功后执行本地事务;
  4. 根据本地事务执行结果返回commit或者是rollback;
  5. 如果消息是rollback, MQ将丢弃该消息不投递;如果是commit,MQ将会消息发送给消息订阅方;
  6. 订阅方根据消息执行本地事务;
  7. 订阅方执行本地事务成功后再从MQ中将该消息标记为已消费;
  8. 如果执行本地事务过程中,执行端挂掉,或者超时,MQ服务器端将不停的询问producer来获取事务状态;
  9. Consumer端的消费成功机制有MQ保证

分布式事务

1、如果是不支持ACK机制或者没有MQ而是通过可靠消息系统直接投递的场景,被通知方服务在处理成功后需要ACK给可靠消息系统,否则可靠消息系统会通过重试保障消息的必达

2、通过mq来进行系统交互,存在的一个比较大的问题就是需要保证消息的有序性,尤其是对kafka这种需要通过业务保证有序性时,需要做好消息的隔离

2.5.1、优点

  • 可用性强,可靠消息服务独立部署,可伸缩
  • 被通知方无改造成本

2.5.2、缺陷

  • 可靠消息服务实现成本高,有技术难度
  • 最终一致性的实时性无法保障
  • 一次事务,需要至少发送两次消息

2.6、最大努力通知

最大努力通知服务是一种较简单也是现实中常用的实现最终一致性的分布式事务解决方案,整个方案分为两个步骤:

  1. 投递消息:业务活动的主动方,在完成业务处理之后,向业务活动的被动方发送消息,允许消息丢失;
  2. 消息补偿:业务活动的被动方,通过一定的策略订单向业务活动主动发发起查询,恢复丢失的业务消息;

如下图是最大努力通知方案的简单流程示意图,注意其中下游系统对应的是活动通知方,而上游系统对应的是被通知方

分布式事务

最大努力通知方案面向的场景和可靠消息方案类似,也是系统间通过异步进行交互,区别在于:

  • 可靠消息系统:关注业务活动的主动方在发消息过程的事务性,业务活动的主动方需要为可靠消息系统提供查询补偿操作
  • 最大努力通知:关注业务活动的被动方是否收到消息,业务活动的主动方需要为被动方提供查询补偿操作

2.6.1、优点

  • 可用性强
  • 支持异步场景
  • 方案简单

2.6.2、缺陷

  • 活动通知方需要提供查询能力,活动被通知放需要实现补偿
  • 下游依赖上游
  • 最终一致性的实时性差