前言

在传统的单体应用架构中,例如经典的SSM,项目会采用分层架构模式:数据库访问层、业务逻辑层、控制层,从前端到后台所有的代码都是一个或者几个开发者去完成,该架构模式没有对我们业务逻辑代码实现拆分、也没有对数据源进行拆分,所有的代码都写入到同一个项目的不同module中。此时多个不同业务逻辑都是在同一个数据源中实现事务管理,是不存在分布式事务的问题,因为在同一个数据源的情况下,都是采用事务管理器,相当于每个事务管理器对应一个数据源。

如果使用分布式、微服务的架构风格来开发项目、在数据源得到足够拆分的情况下,必然会产生分布式事务问题,历来分布式事务是分布式系统中的一大难题,好在是alibaba开源了Seata,可帮助开发团队快速解决分布式事务难题,正好我所开发的项目中产生了分布式事务场景,因此Seata成为了首选,那么在学习Seata之前,我们先通过一篇文章介绍分布式事务相关概念以及常见的解决方案,帮助大家对分布式事务基础概念有个大致的了解。


一、本地事务和分布式事务

在了解什么是分布式事务之前首先要了解以下关于事务的几个概念ACID:

1. 事务

事务是由一组操作构成的可靠的独立的工作单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。事务具备ACID的特性,即原子性、一致性、隔离性和持久性。

  • 原子性A :事务是数据库的逻辑工作单位,不可分割,事务中包含的各操作要么都做,要么都不做,也就是要么全部提交,要么全部回滚
  • 一致性C :指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。举例来说,假设用户A和用户B两者的钱加起来一共是1000,那么不管A和B之间如何转账、转几次账,事务结束后两个用户的钱相加起来应该还得是1000,这就是事务的一致性。
  • 隔离性I :多个事务在一起执行的时候,互不影响,一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性D :事务一旦提交或者回滚后,它对数据库中的数据的改变就应该是永久性的,接下来的其它操作或故障不应该对其执行结果有任何影响

2. 本地事务

本地事务就是用关系数据库来控制事务,关系数据库通常都具有ACID特性,传统的单体应用通常会将数据全部存储在一个数据库中,会借助关系数据库来完成事务控制。


3. 分布式事务

随着业务需求的飞速发展和项目架构发生的巨大变化,单体应用已经完全不能满足业务需求,整体架构由原来的单体应用逐渐拆分成为了微服务,原来的3个服务被从一个单体架构上拆开了,成为了3个独立的微服务,每个微服务分别使用自己的数据库,也不在之前共享同一个数据源了,具体的业务将由三个服务的调用来共同完成,如图:

每一个服务的内部数据一致性仍然由本地事务来保证。但是面对整个业务流程上的事务应该如何保证呢?这就是在微服务架构下面临的挑战,如何保证在微服务中的数据一致性呢?


二、柔性事务和刚性事务

上面丢出一个问题,关于在微服务系统中如何保证数据的一致性问题?要想探究这个问题,我们首先先来了解一下事务中的刚性事务和柔性事务:

  • 柔性事务: 柔性事务遵循BASE理论,满足基本可用,最终一致,与刚性事务不同,柔性事务允许在一定时间内,不同节点的数据不一致,但要求最终一致即可。。
  • 刚性事务: 刚性事务遵循ACID原则,满足强一致性,刚性事务的标准实现有2PC(二阶段提交)和3PC(三阶段提交),常用的关系型数据库事务就是刚性事务、强一致性的典型例子。

柔性事务的实现有: 补偿型、异步确保型、最大努力通知型。

刚性事务的实现有: Undo_log逆向日志回滚(数据库均基于这种方式)、2pc两阶段型、3pc三阶段型。

由于传统项目整个架构是SOA架构,因此传统单机环境下数据库的ACID事务无法满足分布式环境下的业务需要,以上几种事务类似就是针对分布式环境下业务需要设定的。

软状态: 状态有一段时间可以不同步,是异步的。

三、主流分布式事务解决框架

  • 1.单体项目多数据源情况 ,可以使用JTA+ Atomikos,但不适用于分布式系统。
  • 2.基于RabbitMQ的形式解决 ,采用最终一致性的思想。
  • 3.基于RocketMQ解决分布式事务 ,采用可靠性事务消息机制和最终一致性。
  • 4.国产LCN分布式事务框架,采用lcn模式 ,原理使用假关闭连接 (公司倒闭,目前已经被淘汰: http://www.txlcn.org/zh-cn/),理念 “LCN并不生产事务,LCN只是本地事务的协调工” 。
  • 5.Spring Cloud Alibaba开源的Seata ,未来可能是分布式事务的主流解决方案,当下比较推荐。

四、分布式事务核心思想

关于分布式事务解决方案,核心思想有: 2pc(基于两阶段提交协议+最终一致性)、3pc三段提交协议(弥补两端提交协议缺点,如超时)、Tcc(补偿机制)。

1. 2pc两阶段提交方案(XA)

2PC 是二阶段提交(Two-phase Commit)的缩写,分为两个阶段完成,第一个阶段是准备阶段(prepare),第二个阶段是提交阶段(commit/rollback),准备阶段和提交阶段都是由事务管理器(协调者)发起的,协调的对象是资源管理器(参与者),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务,协调者会通过两次阶段实现数据最终的一致性的。

第一阶段

  • 准备阶段

协调者向参与者发起指令,协调者询问参与者事务是否执行成功,参与者发回事务执行结果给协调者,写 redo 和 undo 日志,然后锁定资源,执行操作,但并不提交。

第二阶段

  • 提交阶段

如果事务在每个参与者上都执行成功,每个参与者明确返回准备成功,则协调者向参与者发送提交事务指令,通知让参与者提交事务;否则,若任何一个参与者明确返回准备失败,则协调者发送通知让参与者回滚事务,参与者取消已经变更的事务,执行 undo 日志回滚事务并释放锁定的资源。需要注意的是,在准备阶段,参与者执行了事务,但是还未提交,只是对资源进行锁定。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

2pc优缺点: 虽然2pc两阶段提交方案在分布式系统中被广泛应用,但是从性能角度来讲,两阶段提交方案锁定资源时间长,性能相对差一些,倘若协调者宕机,参与者没有了协调者指挥,则会一直阻塞,从某种意义上来讲两阶段提交牺牲了一部分可用性来换取一致性。 也因此产生了后面的3pc提交方案。

2. 3pc三段提交协议

3pc三阶段提交协议是2pc两阶段提交协议的改进版本。它主要是通过超时机制来解决阻塞的问题,并且通过增加事务询问阶段,把两个阶段增加为三个阶段,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段:

CanCommit阶段

3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

1.事务询问: 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。

2.响应反馈: 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No

PreCommit阶段

协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。
假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。

  • 1.发送预提交请求: 协调者向参与者发送PreCommit请求,并进入Prepared阶段。

  • 2.事务预提交: 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。

  • 3.响应反馈: 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。

  • 1.发送中断请求: 协调者向所有参与者发送abort请求。

  • 2.中断事务: 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

doCommit阶段

该阶段进行真正的事务提交,也可以分为以下两种情况。

Case 1:执行提交

  • 1.发送提交请求: 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。

  • 2.事务提交: 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。

  • 3.响应反馈: 事务提交完之后,向协调者发送Ack响应。

  • 4.完成事务: 协调者接收到所有参与者的ack响应之后,完成事务。

Case 2:中断事务 协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。

  • 1.发送中断请求: 协调者向所有参与者发送abort请求

  • 2.事务回滚: 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。

  • 3.反馈结果: 参与者完成事务回滚之后,向协调者发送ACK消息

  • 4.中断事务: 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。

补充:

在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时,会在等待超时之后,会继续进行事务的提交。(其实这个应该是基于概率来决定的,当进入第三阶段时,说明参与者在第二阶段已经收到了PreCommit请求,那么协调者产生PreCommit请求的前提条件是他在第二阶段开始之前,收到所有参与者的CanCommit响应都是Yes。(一旦参与者收到了PreCommit,意味他知道大家其实都同意修改了)所以,一句话概括就是,当进入第三阶段时,由于网络超时等原因,虽然参与者没有收到commit或者abort响应,但是他有理由相信:成功提交的几率很大。 )

3pc缺点

3PC 通过预提交阶段可以减少故障恢复时候的复杂性,但3PC 还是没能从根本上解决数据一致性的问题,比如在预提交阶段时协调者和其中一个参与者都发生了故障,此时其他参与者在超时情况下会自动选择提交或回滚,当新选举出的协调者上任时也会给活着的参与者发送提交命令,但发生故障的那个参与者还未恢复且无法确定是否执行了事务,这里就出现了数据不一致的情况。

事实上 2PC 和 3PC 都无法保证完全的数据一致性,于是需要利用TCC补偿机制尽量确保数据的一致性。

3. Tcc事务的补偿机制

TCC是Try-Confirm-Cancel的简称:

Try阶段:

完成所有业务检查(一致性),预留业务资源(准隔离性)
回顾上面航班预定案例的阶段1,机票就是业务资源,所有的资源提供者(航空公司)预留都成功,try阶段才算陈宫

Confirm阶段:

确认执行业务操作,不做任何业务检查, 只使用Try阶段预留的业务资源。回顾上面航班预定案例的阶段2,美团APP确认两个航空公司机票都预留成功,因此向两个航空公司分别发送确认购买的请求。

Cancel阶段:
取消Try阶段预留的业务资源。回顾上面航班预定案例的阶段2,如果某个业务方的业务资源没有预留成功,则取消所有业务资源预留请求。

敏锐的读者立马会想到,TCC与XA两阶段提交有着异曲同工之妙,下图列出了二者之间的对比:

1) 在阶段1:
在XA中,各个RM准备提交各自的事务分支,事实上就是准备提交资源的更新操作(insert、delete、update等);而在TCC中,是主业务活动请求(try)各个从业务服务预留资源。

2) 在阶段2
XA根据第一阶段每个RM是否都prepare成功,判断是要提交还是回滚。如果都prepare成功,那么就commit每个事务分支,反之则rollback每个事务分支。

TCC中,如果在第一阶段所有业务资源都预留成功,那么confirm各个从业务服务,否则取消(cancel)所有从业务服务的资源预留请求。

TCC两阶段提交与XA两阶段提交的区别是:

XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。

XA事务中的两阶段提交内部过程是对开发者屏蔽的,回顾我们之前讲解JTA规范时,通过UserTransaction的commit方法来提交全局事务,这只是一次方法调用,其内部会委派给TransactionManager进行真正的两阶段提交,因此开发者从代码层面是感知不到这个过程的。而事务管理器在两阶段提交过程中,从prepare到commit/rollback过程中,资源实际上一直都是被加锁的。如果有其他人需要更新这两条记录,那么就必须等待锁释放。

TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。

TCC中的两阶段提交并没有对开发者完全屏蔽,也就是说从代码层面,开发者是可以感受到两阶段提交的存在。如上述航班预定案例:在第一阶段,航空公司需要提供try接口(机票资源预留)。在第二阶段,航空公司提需要提供confirm/cancel接口(确认购买机票/取消预留)。开发者明显的感知到了两阶段提交过程的存在。try、confirm/cancel在执行过程中,一般都会开启各自的本地事务,来保证方法内部业务逻辑的ACID特性。其中:

1、try过程的本地事务,是保证资源预留的业务逻辑的正确性。

2、confirm/cancel执行的本地事务逻辑确认/取消预留资源,以保证最终一致性,也就是所谓的补偿型事务(Compensation-Based Transactions)。

由于是多个独立的本地事务,因此不会对资源一直加锁。

另外,这里提到confirm/cancel执行的本地事务是补偿性事务,关于什么事补偿性事务,atomikos 官网上有以下描述:

红色框中的内容,是对补偿性事务的解释。大致含义是,"补偿是一个独立的支持ACID特性的本地事务,用于在逻辑上取消服务提供者上一个ACID事务造成的影响,对于一个长事务(long-running transaction),与其实现一个巨大的分布式ACID事务,不如使用基于补偿性的方案,把每一次服务调用当做一个较短的本地ACID事务来处理,执行完就立即提交”。

在这里,笔者理解为confirm和cancel就是补偿事务,用于取消try阶段本地事务造成的影响。因为第一阶段try只是预留资源,之后必须要明确的告诉服务提供者,这个资源你到底要不要,对应第二阶段的confirm/cancel。

提示:读者现在应该明白为什么把TCC叫做两阶段补偿性事务了,提交过程分为2个阶段,第二阶段的confirm/cancel执行的事务属于补偿事务

4. 2PC与3PC提交区别

相对于2PC,3PC增加了一个询问阶段,询问阶段可以确保尽可能早的发现无法执行操作而需要中止的行为,主要解决了单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。

五、总结

  • 本地事务: 一个完整的事务操作可以在同一物理介质(例如:内存)上同时完成;
  • 分布式事务: 一个完整事务需要跨物理介质或跨物理节点(网络通讯)完成;

在分布式事务的定义里,无疑排它锁、共享锁等等就没有用武之地了,无法保证原子性完成事务。为了能够达到原子性的效果,二阶段提交提出了协调者角色,协调者拥有数据读取写入的唯一性。但同时带来了严重的同步阻塞问题,且如果协调者释放读取的能力,则无法保证原子性。

实际在分布式事务的发展过程中,刚性事务只在副本存储等局限场景中使用,柔性事务无疑是主要角色,甚至一般讲分布式事务,就是在讲柔性事务。

在柔性事务中,最重要的无疑是如何实现数据的最终一致性,在之后会另起一章,介绍主流的数据一致性算法,尤其是带有传奇色彩的经典算法-Paxos。

如果对柔性事务与数据一致性算法有更多的兴趣,可以了解一下Basic Paxos、Multi Paxos、Raft(ETCD的方案)、ZAB(Zookeeper的方案)、Gossip(Cassandra的方案)。

六、参考文档

上述理论总结通过参考部分文档学习,如有侵权,请联系删除:
http://www.tianshouzhi.com/
https://blog.csdn.net/wsdc0521/article/details/108097082
https://blog.csdn.net/u014034683/article/details/89422804
https://www.jianshu.com/p/d70df89665b9

SpringCloud Alibaba 微服务架构(十一)- 分布式事务解决方案及理论基础篇相关推荐

  1. Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案

    Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案 说明:Java生鲜电商平台中由于采用了微服务架构进行业务的处理,买家,卖家,配送,销售,供应商等进行服务化,但是不可避免存在 ...

  2. 微服务架构及分布式事务解决方案

    微服务架构及分布式事务解决方案 参考文章: (1)微服务架构及分布式事务解决方案 (2)https://www.cnblogs.com/rinack/p/9734551.html 备忘一下.

  3. 聊聊微服务架构及分布式事务解决方案

    转载自   聊聊微服务架构及分布式事务解决方案 分布式事务场景如何设计系统架构及解决数据一致性问题,个人理解最终方案把握以下原则就可以了,那就是:大事务=小事务(原子事务)+异步(消息通知),解决分布 ...

  4. 微服务架构的分布式事务解决方案

    微服务架构的分布式事务解决方案 参考文章: (1)微服务架构的分布式事务解决方案 (2)https://www.cnblogs.com/lyl2016/p/5908613.html 备忘一下.

  5. 微服务架构的分布式事务解决方案(Dubbo分布式事务处理)

    微服务架构的分布式事务解决方案(Dubbo分布式事务处理) 参考文章: (1)微服务架构的分布式事务解决方案(Dubbo分布式事务处理) (2)https://www.cnblogs.com/qiyu ...

  6. 深入解读微服务架构下分布式事务解决方案

    微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.概念一经提出迅速火遍全球.当前 Hailo 有160个不同服务构成,NetFlix 有大约 ...

  7. 微服务架构下分布式事务解决方案——阿里GTS

    1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,很多互联网行业巨头.开源社区等都开始了微服务 ...

  8. 微服务架构下分布式事务解决方案 —— 阿里GTS

    1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,很多互联网行业巨头.开源社区等都开始了微服务 ...

  9. 进阶必学之微服务架构下分布式事务解决方案,你不知道的58同城

    1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,很多互联网行业巨头.开源社区等都开始了微服务 ...

  10. 微服务架构下分布式事务解决方案——阿里云GTS

    1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,很多互联网行业巨头.开源社区等都开始了微服务 ...

最新文章

  1. UA SIE545 优化理论基础4 对偶理论简介4 求解对偶问题的割平面算法
  2. 损害计算机系统,哪些情况下容易导致电脑系统崩溃损坏?
  3. ASP.NET 中 Cookie 的基本知识
  4. PHP环境搭建:Windows 7下安装配置PHP+Apache+Mysql环境教程
  5. 全国计算机等级考试题库二级C操作题100套(第55套)
  6. NOIP模拟测试49·50「养花·折射·画作·施工·蔬菜·联盟」
  7. Servlet 开发【07】Servlet两种跳转
  8. micropython入门教程-【chocho教程】micropython入门教程一
  9. 神经网络用作分类器(附代码matlab)
  10. 数据分析中会常犯哪些错误,如何解决? 二
  11. 人工智能与机器学习学习笔记(三)
  12. 计算机专用英语词汇1695个词汇表
  13. 怎么在个人网站开通支付宝付款功能
  14. ANC主动降噪耳机有哪些?ANC主动降噪耳机推荐!
  15. 揭密 HAP 激光雷达的实际性能表现
  16. linux命令 ---rm
  17. Android触控基础:MotionEvent
  18. TMS320F28377S 学习笔记2 BGA封装的焊接
  19. 0343基于STM32单片机的茶园大棚环境土壤湿度光强WiFi监测系统proteus仿真原理图PCB
  20. idenet 学习记录:bili

热门文章

  1. 2020李宏毅学习笔记——54.Anomaly Detection(4_7)
  2. Android下创建一个sqlite数据库
  3. 在 macOS 上安装 AWS CLI
  4. 基于Java毕业设计智能推荐二手车交易网站源码+系统+mysql+lw文档+部署软件
  5. HDFS的数据压缩格式
  6. [Codewar练习-jsc++]N Linear(N线性)
  7. nllb-200-distilled-600M语言缩写对照表
  8. Dom.nodeType
  9. Nexus 5X线刷教程
  10. 最新消息!苹果手机也支持微信多开