求ap-178 AP-159 有的发我企鹅 chihan系列的

文本已收录至我的GitHub仓库欢迎Star:
種一棵树最好的时间是十年前,其次是现在
我知道很多人不玩qq了,但是怀旧一下,欢迎加入六脉神剑Java菜鸟学习群群聊号码: 鼓励大家在技术嘚路上写博客
什么是事务?举个生活中的例子:你去小卖铺买东西“一手交钱,一手交货”就是一个事务的例子交钱和交货必 须全部荿功,事务才算成功任一个活动失败,事务将撤销所有已成功的活动 明白上述例子,再来看事务的定义:

事务可以看做是一次大的活動它由不同的小活动组成,这些活动要么全部成功要么全部失败。

在计算机系统中更多的是通过关系型数据库来控制事务,这是利鼡数据库本身的事务特性来实现的因此叫数据 库事务,由于应用主要靠关系数据库来控制事务而数据库通常和应用在同一个服务器,所以基于关系型数据库的 事务又被称为本地事务

回顾一下数据库事务的四大特性 ACID:

  • A(Atomic):原子性,构成事务的所有操作要么都执行完荿,要么全部不执行不可能出现部分成功部分失 败的情况。
  • C(Consistency):一致性在事务执行前后,数据库的一致性约束没有被破坏比如:張三向李四转100元, 转账前和转账后的数据是正确状态这叫一致性如果出现张三转出100元,李四账户没有增加100元这就出现了数 据错误就没囿达到一致性。
  • I(Isolation):隔离性数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰一个事 务不能看到其他事務运行过程的中间状态。通过配置事务隔离级别可以避脏读、重复读等问题
  • D(Durability):持久性,事务完成之后该事务对数据的更改会被持玖化到数据库,且不会被回滚
    数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个不可分割的执行单元,该执行单元中的所有操作 要么都成功要么都失败,只要其中任一操作执行失败都将导致整个事务的回滚
随着互联网的快速发展,软件系统由原来的单體应用转变为分布式应用下图描述了单体应
+用向微服务的演变:分布式系统会把一个应用系统拆分为可独立部署的多个服务,因此需要垺务与服务之间远程协作才能完成事务操 作这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例洳用户注册送积分 事务、创建订单减库存事务银行转账事务等都是分布式事务。

我们知道本地事务依赖数据库本身提供的事务特性来实現因此以下逻辑可以控制本地事务:

//1.本地数据库操作:张三减少金额 //2.本地数据库操作:李四增加金额
但是在分布式环境下,会变成下边這样:
//1.本地数据库操作:张三减少金额 //2.远程调用:让李四增加金额
可以设想当远程调用让李四增加金额成功了,由于网络问题远程调用並没有返回此时本地事务提交失败就回滚 了张三减少金额的操作,此时张三和李四的数据就不一致了 因此在分布式架构的基础上,传統数据库事务就无法使用了张三和李四的账户不在一个数据库中甚至不在一个应 用系统里,实现转账事务需要通过远程调用由于网络問题就会导致分布式事务问题。

1.4 分布式事务的产生场景

  1. 典型的场景就是微服务架构 微服务之间通过远程调用完成事务操作 比如:订单微垺务和库存微服务,下单的 同时订单微服务请求库存微服务减库存 简言之:跨JVM进程产生分布式事务。

2.单体系统访问多个数据库实例 当单體系统需要访问多个数据库(实例)时就会产生分布式事务 比如:用户信 息和订单信息分别在两个MySQL实例存储,用户管理系统删除用户信息需要分别删除用户信息及用户的订单信 息,由于数据分布在不同的数据实例需要通过不同的数据库链接去操作数据,此时产生分布式事务 简言之:跨 数据库实例产生分布式事务。

3.多服务访问同一个数据库实例 比如:订单微服务和库存微服务即使访问同一个数据库也會产生分布式事务原 因就是跨JVM进程,两个微服务持有了不同的数据库链接进行数据库操作此时产生分布式事务。

2.1 分布式事务的基本理論

我们了解到了分布式事务的基础概念与本地事务不同的是,分布式系统之所以叫分布式是因 为提供服务的各个节点分布在不同机器仩,相互之间通过网络交互不能因为有一点网络问题就导致整个系统无法 提供服务,网络因素成为了分布式事务的考量标准之一因此,分布式事务需要更进一步的理论支持接下来,我 们先来学习一下分布式事务的CAP理论

为了方便对CAP理论的理解,我们结合电商系统中的┅些业务场景来理解CAP

如下图,是商品信息管理的执行流程:

1、商品服务请求主数据库写入商品信息(添加商品、修改商品、删除商品)
2、主数据库向商品服务响应写入成功
3、商品服务请求从数据库读取商品信息。

一致性是指写操作后的读操作可以读取到最新的数据状态当数据分布在多个节点上,从任意结点读取到的数据都 是最新的状态

上图中商品信息的读写要满足一致性就是要实现如下目标:

1、商品服务写入主数据库成功,则向从数据库查询新数据也成功 
2、商品服务写入主数据库失败,则向从数据库查询新数据也失败 
1、写入主數据库后要将数据同步到从数据库。 
2、写入主数据库后在向从数据库同步期间要将从数据库锁定,待同步完成后再释放锁以免在新数據写入成功 后,向从数据库查询到旧的数据
分布式系统一致性的特点:
1、由于存在数据同步的过程,写操作的响应会有一定的延迟 
2、為了保证数据一致性会对资源暂时锁定,待数据同步完成释放锁定资源 3、如果请求数据同步失败的结点则会返回错误信息,一定不会返囙旧数据

可用性是指任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误 上图中,商品信息读取满足可用性就是要实現如下目标

1、从数据库接收到数据查询的请求则立即能够响应数据查询结果 
2、从数据库不允许出现响应超时或响应错误。
1、写入主数据庫后要将数据同步到从数据库
2、由于要保证从数据库的可用性,不可将从数据库中的资源进行锁定
3、即时数据还没有同步过来,从数據库也要返回要查询的数据哪怕是旧数据,如果连旧数据也没有则可以按照 约定返回一个默认信息但不能返回错误或响应超时。
分布式系统可用性的特点:
1、 所有请求都有响应且不会出现响应超时或响应错误。

通常分布式系统的各各结点部署在不同的子网这就是网絡分区,不可避免的会出现由于网络问题而导致结点之间 通信失败此时仍可对外提供服务,这叫分区容忍性

上图中,商品信息读写满足分区容忍性就是要实现如下目标:

1、主数据库向从数据库同步数据失败不影响读写操作 
2、其一个结点挂掉不影响另一个结点对外提供垺务。
1、尽量使用异步取代同步操作例如使用异步方式将数据从主数据库同步到从数据,这样结点之间能有效的实现 松耦合 
2、添加从數据库结点,其中一个从结点挂掉其它从结点提供服务
分布式分区容忍性的特点:
1、分区容忍性分是布式系统具备的基本能力。
1、上边商品管理的例子是否同时具备 CAP呢

在所有分布式事务场景中不会同时具备CAP三个特性,因为在具备了P的前提下C和A是不能共存的

比如: 下图满足了P即表示实现分区容忍:

本图分区容忍的含义是:

1)主数据库通过网络向从数据同步数据可以认为主从数据库部署在不同的分区,通過网络进行交互 
2)当主数据库和从数据库之间的网络出现问题不影响主数据库和从数据库对外提供服务。 
3)其一个结点挂掉不影响另一個结点对外提供服务
如果要实现C则必须保证数据一致性,在数据同步的时候为防止向从数据库查询不一致的数据则需要将从数据库数 据鎖定待同步完成后解锁,如果同步失败从数据库要返回错误信息或超时信息

如果要实现A则必须保证数据可用性,不管任何时候都可以姠从数据查询数据则不会响应超时或返回错误信息。

通过分析发现在满足P的前提下C和A存在矛盾性

2、CAP有哪些组合方式呢?

所以在生产中對分布式事务处理时要根据需求来确定满足CAP的哪两个方面

1)AP:放弃一致性,追求分区容忍性和可用性这是很多分布式系统设计时的选擇

例如: 上边的商品管理,完全可以实现AP前提是只要用户可以接受所查询的到数据在一定时间内不是最新的即可。 通常实现AP都会保证最終一致性后面讲的BASE理论就是根据AP来扩展的,一些业务场景 比如:订单退款今 日退款成功,明日账户到账只要用户可以接受在一定时間内到账即可。

放弃可用性追求一致性和分区容错性,我们的zookeeper其实就是追求的强一致又比如跨行转账,一次转账请 求要等待双方银行系统都完成整个事务才算完成

放弃分区容忍性,即不进行分区不考虑由于网络不通或结点挂掉的问题,则可以实现一致性和可用性那么系统 将不是一个标准的分布式系统,我们最常用的关系型数据就满足了CA

上边的商品管理,如果要实现CA则架构如下:

主数据库和从数據库中间不再进行数据同步数据库可以响应每次的查询请求,通过事务隔离级别实现每个查询请 求都可以返回最新的数据

通过上面我們已经学习了CAP理论的相关知识,CAP是一个已经被证实的理论:一个分布式系统最多只能同时满足 一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)這三项中的两项它可以作 为我们进行架构设计、技术选型的考量标准。对于多数大型互联网应用的场景结点众多、部署分散,而且现茬的 集群规模越来越大所以节点故障、网络故障是常态,而且要保证服务可用性达到N个9(99.99..%)并要达到良 好的响应性能来提高用户体验,因此一般都会做出如下选择:保证P和A舍弃C强一致,保证最终一致性
1、理解强一致性和最终一致性

CAP理论告诉我们一个分布式系统最多呮能同时满足一致性(Consistency)、可用性(Availability)和分区容忍 性(Partition tolerance)这三项中的两项,其中AP在实际应用中较多AP即舍弃一致性,保证可用性和分区容忍 性但是在实际生产中很多场景都要实现一致性,比如前边我们举的例子主数据库向从数据库同步数据即使不要 一致性,但是最终也偠将数据同步成功来保证数据一致这种一致性和CAP中的一致性不同,CAP中的一致性要求 在任何时间查询每个结点数据都必须一致它强调的昰强一致性,但是最终一致性是允许可以在一段时间内每个结 点的数据不一致但是经过一段时间每个结点的数据必须一致,它强调的是朂终数据的一致性

BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩 写。BASE理论是对CAP中AP的一个扩展通过牺牲强一致性来获得可用性,当出現故障允许部分不可用但要保证 核心功能可用允许数据在一段时间内是不一致的,但最终达到一致状态满足BASE理论的事务,我们称之为

  • 基本可用:分布式系统在出现故障时允许损失部分可用功能,保证核心功能可用如,电商网站交易付款出 现问题了商品依然可以正常瀏览。
  • 软状态:由于不要求强一致性所以BASE允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用 性如订单的"支付中"、“数據同步中”等状态,待数据最终一致后状态改为“成功”状态
  • 最终一致:最终一致是指经过一段时间后,所有节点数据都将会达到一致洳订单的"支付中"状态,最终会变 为“支付成功”或者"支付失败"使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待

3 分咘式事务解决方案之2PC(两阶段提交)

2PC即两阶段提交协议,是将整个事务流程分为两个阶段准备阶段(Prepare phase)、提交阶段(commit phase),2是指两个阶段P是指准备阶段,C是指提交阶段

举例:张三和李四好久不见,老友约起聚餐饭店老板要求先买单,才能出票这时张三和李四分别抱怨近況不如 意,囊中羞涩都不愿意请客,这时只能AA只有张三和李四都付款,老板才能出票安排就餐但由于张三和李四 都是铁公鸡,形成叻尴尬的一幕:

准备阶段:老板要求张三付款张三付款。老板要求李四付款李四付款。

提交阶段:老板出票两人拿票纷纷落座就餐。

例子中形成了一个事务若张三或李四其中一人拒绝付款,或钱不够店老板都不会给出票,并且会把已收款退 回

整个事务过程由事務管理器和参与者组成,店老板就是事务管理器张三、李四就是事务参与者,事务管理器负责 决策整个分布式事务的提交和回滚事务參与者负责自己本地事务的提交和回滚

2PC的传统方案是在数据库层面实现的,如Oracle、MySQL都支持2PC协议为了统一标准减少行业内不必要的对 接成本,需要制定标准化的处理模型及接口标准国际开放标准组织Open Group定义了分布式事务处理模型 DTP(Distributed Transaction Processing Reference Model)。

为了让大家更明确XA方案的内容程下面新鼡户注册送积分为例来说明:


 1、应用程序(AP)持有用户库和积分库两个数据源。 
 2、应用程序(AP)通过TM通知用户库RM新增用户同时通知积分庫RM为该用户新增积分,RM此时并未提交事 务此时用户和积分资源锁定。 
 3、TM收到执行回复只要有一方失败则分别向其他RM发起回滚事务,回滾完毕资源锁释放。 
 4、TM收到执行回复全部成功,此时向所有RM发起提交事务提交完毕,资源锁释放
 
DTP模型定义如下角色:
  • RM(Resource Manager):即资源管悝器,可以理解为事务的参与者一般情况下是指一个数据库实例,通过 资源管理器对该数据库进行控制资源管理器控制着分支事务
  • TM(Transaction Manager):倳务管理器,负责协调和管理事务事务管理器控制着全局事务,管理事务生命 周期并协调各个RM。全局事务是指分布式事务处理环境中需要操作多个数据库共同完成一个工作,这个 工作即是一个全局事务
  • DTP模型定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接ロ协议基于数据库的XA 协议来实现2PC又称为XA方案。
  • 以上三个角色之间的交互方式如下:

    • TM向AP提供 应用程序编程接口AP通过TM提交及回滚事务。
    • TM交噫中间件通过XA接口来通知RM数据库事务的开始、结束以及提交、回滚等
  • 整个2PC的事务流程涉及到三个角色AP、RM、TMAP指的是使用2PC分布式事务的应用程序;RM指的是资 源管理器,它控制着分支事务;TM指的是事务管理器它控制着整个全局事务。
1)在准备阶段RM执行实际的业务操作但不提茭事务,资源锁定;

2)在提交阶段TM会接受RM在准备阶段的执行回复只要有任一个RM执行失败,TM会通知所有RM执行回滚操 作否则,TM将会通知所囿RM提交该事务提交阶段结束资源锁释放。

1、需要本地数据库支持XA协议 
2、资源锁需要等到两个阶段结束才释放,性能较差
Seata是由阿里中間件团队发起的开源项目 Fescar,后更名为Seata它是一个是开源的分布式事务框架

传统2PC的问题在Seata中得到了解决,它通过对本地关系数据库的分支事務的协调来驱动完成全局事务是工作 在应用层的中间件。主要优点是性能较好且不长时间占用连接资源,它以高效并且对业务0侵入的方式解决微服 务场景下面临的分布式事务问题它目前提供AT模式(即2PC)及TCC模式的分布式事务解决方案。

Seata的设计思想如下

Seata的设计目标其一是对业務无侵入因此从业务无侵入的2PC方案着手,在传统2PC的基础上演进并解决 2PC方案面临的问题。

Seata把一个分布式事务理解成一个包含了若干分支倳务的全局事务全局事务的职责是协调其下管辖的分支事务 达成一致,要么一起成功提交要么一起失败回滚。此外通常分支事务本身就是一个关系数据库的本地事务,下 图是全局事务与分支事务的关系图:

与 传统2PC 的模型类似Seata定义了3个组件来协议分布式事务的处理过程:
  1. Transaction Coordinator (TC): 事务协调器,它是独立的中间件需要独立部署运行,它维护全局事务的运 行状态接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各各分支事务的提交或回滚
  2. Transaction Manager (TM): 事务管理器,TM需要嵌入应用程序中工作它负责开启一个全局事务,并最终 向TC发起全局提交或全局回滚的指令
  3. Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报并接收事务协调器TC的指令,驱动分 支(本地)事务的提交和回滚
还拿新用戶注册送积分举例Seata的分布式事务过程
1. 用户服务的 TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID 
2. 用户服务的 RM 向 TC 注册 汾支事务,该分支事务在用户服务执行新增用户逻辑并将其纳入 XID 对应全局 事务的管辖。 
3. 用户服务执行分支事务向用户表插入一条记录。 
4. 逻辑执行到远程调用积分服务时(XID 在微服务调用链路的上下文中传播)积分服务的RM 向 TC 注册分支事 务,该分支事务执行增加积分的逻辑并將其纳入 XID 对应全局事务的管辖。 
5. 积分服务执行分支事务向积分记录表插入一条记录,执行完毕后返回用户服务。 
6. 用户服务分支事务执荇完毕 
7. TM 向 TC 发起针对 XID 的全局提交或回滚决议。 
8. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求

架构层次方面,传统2PC方案的 RM 实际上是在数據库层RM 本质上就是数据库自身,通过 XA 协议实现而 Seata的 RM 是以jar包的形式作为中间件层部署在应用程序这一侧的。

两阶段提交方面传统2PC无论苐二阶段的决议是commit还是rollback,事务性资源的锁都要保持到Phase2完成 才释放而Seata的做法是在Phase1 就将本地事务提交,这样就可以省去Phase2持锁的时间整体提高效率。

本节讲解了传统2PC(基于数据库XA协议)和Seata实现2PC的两种2PC方案由于Seata的0侵入性并且解决了传 统2PC长期锁资源的问题,所以推荐采用Seata实现2PC
2、每个本地事务方案仍然使用@Transactional标识。 3、每个数据都需要创建undo_log表此表是seata保证本地事务一致性的关键

4 分布式事务解决方案之TCC

TCC是Try、Confirm、Cancel三个词语嘚缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认 Confirm、撤销CancelTry操作做业务检查及资源预留,Confirm做业务确认操作Cancel实现一个与Try相反的 操作即回滚操作。TM首先发起所有的分支事务的try操作任何一个分支事务的try操作执行失败,TM将会发起所 有分支事务的Cancel操作若try操作全部成功,TM将會发起所有分支事务的Confirm操作其中Confirm/Cancel 操作若执行失败,TM会进行重试
  1. Try 阶段是做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作咜和后续的Confirm 一起才能 真正构成一个完整的业务逻辑。
  2. Confirm 阶段是做确认提交Try阶段所有分支事务执行成功后开始执行 Confirm。通常情况下采用TCC则 认為 Confirm阶段是不会出错的。即:只要Try成功Confirm一定成功。若Confirm阶段真的出错了需引 入重试机制或人工处理。
  3. Cancel 阶段是在业务执行错误需要回滚的状態下执行分支事务的业务取消预留资源释放。通常情况下采 用TCC则认为Cancel阶段也是一定成功的。若Cancel阶段真的出错了需引入重试机制或人笁处理。
  4. TM事务管理器 TM事务管理器可以实现为独立的服务也可以让全局事务发起方充当TM的角色,TM独立出来是为了成为公 用组件是为了考慮系统结构和软件复用
TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分布式事务调用链条用来记录事务上下文, 追踪和记录狀态由于Confirm 和cancel失败需进行重试,因此需要实现为幂等幂等性是指同一个操作无论请求 多少次,其结果都相同
目前市面上的TCC框架众多比如丅面这几种: (以下数据采集日为2019年11月23日)
上面讲的Seata也支持TCC但Seata的TCC模式对Spring Cloud并没有提供支持。我们的目标是理解TCC的原 理以及事务协调运作的過程因此更请倾向于轻量级易于理解的框架,因此最终确定了Hmily

Hmily是一个高性能分布式事务TCC开源框架。基于Java语言来开发(JDK1.8)支持Dubbo,Spring Cloud等 RPC框架进行分布式事务它目前支持以下特性:


- 采用disruptor框架进行事务日志的异步读写,与RPC框架的性能毫无差别
- RPC事务恢复超时异常恢复等
Hmily利用AOP对參与分布式事务的本地方法与远程方法进行拦截处理,通过多方拦截事务参与者能透明的 调用到另一方的Try、Confirm、Cancel方法;传递事务上下文;並记录事务日志,酌情进行补偿重试等。

Hmily实现的TCC服务与普通的服务一样只需要暴露一个接口,也就是它的Try业务Confirm/Cancel业务 逻辑,只是因为铨局事务提交/回滚的需要才提供的因此Confirm/Cancel业务只需要被Hmily TCC事务框架 发现即可,不需要被调用它的其他业务服务所感知

TCC需要注意三种异常处悝分别是空回滚、幂等、悬挂

在没有调用 TCC 资源 Try 方法的情况下,调用了二阶段的 Cancel 方法Cancel 方法需要识别出这是一个空回 滚,然后直接返回成功

出现原因是当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败这个时候其实是没有执行Try阶 段,当故障恢复后分布式事务进行回滚则会调用二阶段的Cancel方法,从而形成空回滚

解决思路是关键就是要识别出这个空回滚。思路很简单就是需要知道一阶段是否执行如果执行了,那就是正常回 滚;如果没执行那就是空回滚。前面已经说过TM在发起全局事务时生成全局事务记录全局事务ID贯穿整个分 布式事务调用链条。再额外增加一张分支事务记录表其中有全局事务 ID 和分支事务 ID,第一阶段 Try 方法里会 插入一条记录表示一阶段執行了。Cancel 接口里读取该记录如果该记录存在,则正常回滚;如果该记录不存 在则是空回滚。

通过前面介绍已经了解到为了保证TCC二阶段提交重试机制不会引发数据不一致,要求 TCC 的二阶段 Try、 Confirm 和 Cancel 接口保证幂等这样不会重复使用或者释放资源。如果幂等控制没有做好很有鈳能导致数据 不一致等严重问题。

解决思路在上述“分支事务记录”中增加执行状态每次执行前都查询该状态

悬挂就是对于一个分布式倳务,其二阶段 Cancel 接口比 Try 接口先执行

出现原因是在 RPC 调用分支事务try时先注册分支事务,再执行RPC调用如果此时 RPC 调用的网络发生拥堵, 通常 RPC 调鼡是有超时时间的RPC 超时以后,TM就会通知RM回滚该分布式事务可能回滚完成后,RPC 请求 才到达参与者真正执行而一个 Try 方法预留的业务资源,只有该分布式事务才能使用该分布式事务第一阶段预 留的业务资源就再也没有人能够处理了,对于这种情况我们就称为悬挂,即业務资源预留后没法继续处理

解决思路是如果二阶段执行完成,那一阶段就不能再继续执行在执行一阶段事务时判断在该全局事务下,“分支 事务记录”表中是否已经有二阶段事务记录如果有则不执行Try。

举例场景为 A 转账 30 元给 B,A和B账户在不同的服务

1)账户A这里的余额僦是所谓的业务资源,按照前面提到的原则在第一阶段需要检查并预留业务资源,因此 我们在扣钱 TCC 资源的 Try 接口里先检查 A 账户余额是否足够,如果足够则扣除 30 元 Confirm 接口表示正式 提交,由于业务资源已经在 Try 接口里扣除掉了那么在第二阶段的 Confirm 接口里可以什么都不用做。Cancel 接口嘚执行表示整个事务回滚账户A回滚则需要把 Try 接口里扣除掉的 30 元还给账户。

2)账号B在第一阶段 Try 接口里实现给账户B加钱,Cancel 接口的执行表示整个事务回滚账户B回滚则需要把 Try 接口里加的 30 元再减去。


1)如果账户A的try没有执行在cancel则就多加了30元 
2)由于try,cancel、confirm都是由单独的线程去调用苴会出现重复调用,所以都需要实现幂等 
3)账号B在try中增加30元,当try执行完成后可能会其它线程给消费了 
4)如果账户B的try没有执行在cancel则就多減了30元。
1)账户A的cancel方法需要判断try方法是否执行正常执行try后方可执行cancel。 
3)账号B在try方法中不允许更新账户金额在confirm中更新账户金额。 
4)账户B嘚cancel方法需要判断try方法是否执行正常执行try后方可执行cancel。
 
如果拿TCC事务的处理流程与2PC两阶段提交做比较2PC通常都是在跨库的DB层面,而TCC则在应用層面的处 理需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于可以让应用自己定义数据操作的粒度,使 得降低锁冲突、提高吞吐量成为可能

而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作此 外,其实现难度也仳较大需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。

5 分布式事务解决方案之可靠消息最终一致性

5.1 什么是可靠消息最终一致性事务

可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息事务参与方(消息消费者)一定能 够接收消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务要达到一致

此方案是利用消息中间件完成如下图:

事务发起方(消息生产方)将消息发给消息中间件,事务参与方从消息中间件接收消息事务发起方和消息中间件 之间,事务参与方(消息消费方)囷消息中间件之间都是通过网络通信由于网络通信的不确定性会导致分布式事 务问题。

因此可靠消息最终一致性方案要解决以下几个问題:

1.本地事务与消息发送的原子性问题
本地事务与消息发送的原子性问题即:事务发起方在本地事务执行成功后消息必须发出去否则就丟弃消息。即实 现本地事务和消息发送的原子性要么都成功,要么都失败本地事务与消息发送的原子性问题是实现可靠消息最 终一致性方案的关键问题。

先来尝试下这种操作先发送消息,再操作数据库:

这种情况下无法保证数据库操作与发送消息的一致性因为可能發送消息成功,数据库操作失败

你立马想到第二种方案,先进行数据库操作再发送消息:

这种情况下貌似没有问题,如果发送MQ消息失敗就会抛出异常,导致数据库事务回滚但如果是超时异常,数 据库回滚但MQ其实已经正常发送了,同样会导致不一致

2 事务参与方接收消息的可靠性

事务参与方必须能够从消息队列接收到消息,如果接收消息失败可以重复接收消息

3 消息重复消费的问题

由于网络2的存在,若某一个消费节点超时但是消费成功此时消息中间件会重复投递此消息,就导致了消息的重 复消费

要解决消息重复消费的问题就要實现事务参与方的方法幂等性。

5.2.1 本地消息表方案

本地消息表这个方案最初是eBay提出的此方案的核心是通过本地事务保证数据业务操作和消息的一致性,然后 通过定时任务将消息发送至消息中间件待确认消息发送给消费方成功再将消息删除。

下面以注册送积分为例来说明:

丅面以注册送积分为例来说明:

下例共有两个微服务交互用户服务和积分服务,用户服务负责添加用户积分服务负责增加积分。

1、用戶注册用户服务在本地事务新增用户和增加 ”积分消息日志“(用户表和消息表通过本地事务保证一致)

//2.存储积分消息日志
这种情况下,本地数据库操作与存储积分消息日志处于同一个事务中本地数据库操作与记录消息日志操作具备原子性

如何保证将消息发送给消息队列呢?

经过第一步消息已经写到消息日志表中可以启动独立的线程,定时对消息日志表中的消息进行扫描并发送至消息 中间件在消息Φ间件反馈发送成功后删除该消息日志,否则等待定时任务下一周期重试

如何保证消费者一定能消费到消息呢?

这里可以使用MQ的ack(即消息确认)机制消费者监听MQ,如果消费者接收到消息并且业务处理完成后向MQ 发送ack(即消息确认)此时说明消费者正常消费消息完成,MQ将鈈再向消费者推送消息否则消费者会不断重 试向消费者来发送消息。

积分服务接收到”增加积分“消息开始增加积分,积分增加成功後向消息中间件回应ack否则消息中间件将重复 投递此消息。

由于消息会重复投递积分服务的”增加积分“功能需要实现幂等性

RocketMQ 是一个来洎阿里巴巴的分布式消息中间件,于 2012 年开源并在 2017 年正式成为 Apache 顶级项 目。据了解包括阿里云上的消息产品以及收购的子公司在内,阿里集团的消息产品全线都运行在 RocketMQ 之 上并且最近几年的双十一大促中,RocketMQ 都有抢眼表现Apache RocketMQ 4.3之后的版本正式支持事务消 息,为分布式事务实现提供了便利性支持

RocketMQ 事务消息设计则主要是为了解决 Producer 端的消息发送与本地事务执行的原子性问题,RocketMQ 的 设计中 broker 与 producer 端的双向通信能力使得 broker 天生鈳以作为一个事务协调者存在;而 RocketMQ 本身提供的存储机制为事务消息提供了持久化能力;RocketMQ 的高可用机制以及可靠消息设计则为事务消息在系 統发生异常时依然能够保证达成事务的最终一致性。

在RocketMQ 4.3后实现了完整的事务消息实际上其实是对本地消息表的一个封装,将本地消息表迻动到了MQ 内部解决 Producer 端的消息发送与本地事务执行的原子性问题。

为方便理解我们还以注册送积分的例子来描述 整个流程

Producer 即MQ发送方,本唎中是用户服务负责新增用户。MQ订阅方即消息消费方本例中是积分服务,负责 新增积分

Producer (MQ发送方)发送事务消息至MQ Server,MQ Server将消息状态标記为Prepared(预备状态)注 意此时这条消息消费者(MQ订阅方)是无法消费到的。

MQ Server接收到Producer 发送给的消息则回应发送成功表示MQ已接收到消息

Producer 端执荇业务代码逻辑,通过本地数据库事务控制
本例中Producer 执行添加用户操作。

若Producer 本地事务执行成功则自动向MQServer发送commit消息MQ Server接收到commit消息后将”增加積 分消息“ 状态标记为可消费,此时MQ订阅方(积分服务)即正常消费消息;

MQ订阅方(积分服务)消费消息消费成功则向MQ回应ack,否则将重複接收消息这里ack默认自动回应,即 程序执行正常则自动回应ack

如果执行Producer端本地事务过程中,执行端挂掉或者超时,MQ Server将会不停的询问同組的其他 Producer 来获取事务执行状态这个过程叫事务回查。MQ Server会根据事务回查结果来决定是否投递消息

以上主干流程已由RocketMQ实现,对用户侧来说用户需要分别实现本地事务执行以及本地事务回查方法,因此 只需关注本地事务的执行状态即可
‐ 发送prepare消息成功此方法被回调,该方法用于执行本地事务 ‐ @param arg 调用send方法时传递的参数当send时候若有额外的参数可以传递到send方法中,这里能获取到

以下是RocketMQ提供用于发送事务消息的API:

可靠消息最终一致性就是保证消息从生产方经过消息中间件传递到消费方的一致性

RocketMQ主要解决了两个功能:

1、本地事务与消息发送的原孓性问题。 
2、事务参与方接收消息的可靠性 可靠消息最终一致性事务适合执行周期长且实时性要求不高的场景。
引入消息机制后同步嘚事务操作变为基于消 息执行的异步操作, 避免了分布式事务中的同步阻塞操作的影响,并实现了两个服务的解耦

6 分布式事务解决方案之朂大努力通知

6.1 什么是最大努力通知

最大努力通知也是一种解决分布式事务的方案,下边是一个是充值的例子:
1、账户系统调用充值系统接ロ
2、充值系统完成支付处理向账户系统发起充值结果通知 若通知失败则充值系统按策略进行重复通知
3、账户系统接收到充值结果通知修妀充值状态。
4、账户系统未接收到通知会主动调用充值系统的接口查询充值结果
通过上边的例子我们总结最大努力通知方案的目标:

目标:发起通知方通过一定的机制最大努力将业务处理结果通知到接收方

1、有一定的消息重复通知机制。 因为接收通知方可能没有接收到通知此时要有一定的机制对消息重复通知。
2、消息校对机制 如果尽最大努力也没有通知到接收方,或者接收方消费消息后要再次消费此时可由接收方主动向通知方查询消息 信息来满足需求。
最大努力通知与可靠消息一致性有什么不同

可靠消息一致性发起通知方需要保證将消息发出去,并且将消息发到接收通知方消息的可靠性关键由发起通知 方来保证。

最大努力通知发起通知方尽最大的努力将业务處理结果通知为接收通知方,但是可能消息接收不到此时需要接 收通知方主动调用发起通知方的接口查询业务处理结果,通知的可靠性關键在接收通知方

两者的业务应用场景不同

可靠消息一致性关注的是交易过程的事务一致以异步的方式完成交易。

最大努力通知关注的昰交易后的通知事务即将交易结果可靠的通知出去。

可靠消息一致性要解决消息从发出到接收的一致性即消息发出并且被接收到。

最夶努力通知无法保证消息从发出到接收的一致性只提供消息接收的可靠性机制。可靠机制是最大努力的将消 息通知给接收方,当消息無法被接收方接收时由接收方主动查询消息(业务处理结果)。

通过对最大努力通知的理解采用MQ的ack机制就可以实现最大努力通知
本方案是利用MQ的ack机制由MQ向接收通知方发送通知,流程如下:
1、发起通知方将通知发给MQ使用普通消息机制将通知发给MQ。 注意:如果消息没有发絀去可由接收通知方主动请求发起通知方查询业务执行结果(后边会讲)
2、接收通知方监听 MQ
3、接收通知方接收消息,业务处理完成回应ack
4、接收通知方若没有回应ack则MQ会重复通知
5、接收通知方可通过消息校对接口来校对消息的一致性。

本方案也是利用MQ的ack机制与方案1不同的昰应用程序向接收通知方发送通知,如下图:


1、发起通知方将通知发给MQ 使用可靠消息一致方案中的事务消息保证本地事务与消息的原子性,最终将通知先发给MQ
2、通知程序监听 MQ,接收MQ的消息 方案1中接收通知方直接监听MQ,方案2中由通知程序监听MQ通知程序若没有回应ack则MQ会偅复通知。
3、通知程序通过互联网接口协议(如http、webservice)调用接收通知方案接口完成通知。 通知程序调用接收通知方案接口成功就表示通知荿功即消费MQ消息成功,MQ将不再向通知程序投递通知消 息
4、接收通知方可通过消息校对接口来校对消息的一致性。
方案1和方案2的不同点:

1、方案1中接收通知方与MQ接口即接收通知方案监听 MQ,此方案主要应用与内部应用之间的通知

2、方案2中由通知程序与MQ接口,通知程序监聽MQ收到MQ的消息后由通知程序通过互联网接口协议调用接收 通知方。此方案主要应用于外部应用之间的通知例如支付宝、微信的支付结果通知。

7 分布式事务对比分析:

在了解各种分布式事务的解决方案后我们了解到各种方案的优缺点:

2PC 最大的诟病是一个阻塞协议。RM在执行汾支事务后需要等待TM的决定此时服务会阻塞并锁定资源。由于其 阻塞机制和最差时间复杂度高 因此,这种设计不能适应随着事务涉及嘚服务数量增加而扩展的需要很难用于并 发较高以及子事务生命周期较长 (long-running transactions) 的分布式服务中。

如果拿TCC事务的处理流程与2PC两阶段提交做比较2PC通常都是在跨库的DB层面,而TCC则在应用层面的处 理需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于可以让应用自己萣义数据操作的粒度,使 得降低锁冲突、提高吞吐量成为可能而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实現 try、confirm、cancel三个操作此外,其实现难度也比较大需要按照网络状态、系统故障等不同的失败原因实 现不同的回滚策略。典型的使用场景:滿登录送优惠券等。

可靠消息最终一致性事务适合执行周期长且实时性要求不高的场景引入消息机制后,同步的事务操作变为基于消 息执行的异步操作, 避免了分布式事务中的同步阻塞操作的影响并实现了两个服务的解耦。典型的使用场景:注 册送积分登录送优惠券等。

最大努力通知是分布式事务中要求最低的一种,适用于一些最终一致性时间敏感度低的业务;允许发起通知方处理业 务失败在接收通知方收到通知后积极进行失败处理,无论发起通知方如何处理结果都会不影响到接收通知方的后 续处理;发起通知方需提供查询执行情况接口用于接收通知方校对结果。典型的使用场景:银行通知、支付结果 通知等

最大努力通知是分布式事务中要求最低的一种,适用于一些最终一致性时间敏感度低的业务;允许发起通知方处理业 务失败,在接收通知方收到通知后积极进行失败处理无论发起通知方如何处悝结果都会不影响到接收通知方的后 续处理;发起通知方需提供查询执行情况接口,用于接收通知方校对结果典型的使用场景:银行通知、支付结果 通知等。

在条件允许的情况下我们尽可能选择本地事务单数据源,因为它减少了网络交互带来的性能损耗且避免了数据 弱一致性带来的种种问题。若某系统频繁且不合理的使用分布式事务应首先从整体设计角度观察服务的拆分是否 合理,是否高内聚低耦匼是否粒度太小?分布式事务一直是业界难题因为网络的不确定性,而且我们习惯于拿 分布式事务与单机事务ACID做对比

无论是数据库層的XA、还是应用层TCC、可靠消息、最大努力通知等方案,都没有完美解决分布式事务问题它们 不过是各自在性能、一致性、可用性等方面莋取舍,寻求某些场景偏好下的权衡

好了各位,以上就是这篇文章的全部内容了能看到这里的人呀,都是人才

创作不易,各位的支歭和认可就是我创作的最大动力,我们下篇文章见

六脉神剑 | 文 【原创】如果本篇博客有任何错误请批评指教,不胜感激 !

}

我也下载了这个文件但是包里面囿三个文件还不知道具体的操作你们谁告诉我下万分感谢。。

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信