精华内容
下载资源
问答
  • LCN分布式事务

    2020-05-12 11:39:03
    1.什么分布式事务? 分布式事务是指事务参与者、支持事务服务器、资源服务器以及事务管理器分别位于不同分布式系统不同节点上。 例子:电商系统订单系统和库存系统 图包含了库存和订单两个独立...

    一、分布式事务的介绍

    数据库的事务ACID:原子性,隔离性,一致性,持久性。
    事务的隔离级别:脏读,不可重复读,幻读
    在这里插入图片描述

    1.什么是分布式事务?

    分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点上。
    例子:电商系统的订单系统和库存系统
    在这里插入图片描述
    图中包含了库存和订单两个独立的微服务,每个微服务维护了自己的数据库。在交易系统的业务逻辑中,一个商品在下单之前需要先调用库存服务,进行扣除库存,在调用订单服务,创建订单记录。
    在这里插入图片描述
    正常情况下,两个数据库各自更新成功,两边的数据维持着一致性。
    如果在非正常情况下,可能库存的扣减完成,随后的订单记录却因为某些原因插入失败。或者订单创建成功,但是库存扣减的数据量失败,这时两边的数据量失去了应有的一致性。
    在这里插入图片描述
    这时候就绪哟为了保证事务的一致性,单数据源的用单机事务来保证,多数据源就需要依赖分布式事务来处理。

    2. 分布式事务处理的方式

    1)XA的两阶段提交方案

    A) 基本概念

            XA 协议由 OracleTuxedo 首先提出的,并交给 X/Open 组织,作为资源管理器(数据库) 与事务管理器的接口标准。目前,Oracle、Informix、DB2 和 Sybase 等各大数据库厂家都提 供对 XA 的支持。XA 协议采用两阶段提交方式来管理分布式事务。XA 接口提供资源管理 器与事务管理器之间进行通信的标准接口。
            XA 就是 X/OpenDTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交 易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA 接口函数由数据库厂 商提供。
            X/Open 组织(即现在的 OpenGroup)定义了分布式事务处理模型。X/Open DTP 模型 (1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理 器(CRM)四部分。一般常见的事务管理器(TM)是交易中间件,常见的资源管理器(RM) 是数据库,常见的通信资源管理器(CRM)是消息中间件

    B)XA协议的一阶段提交

    在这里插入图片描述
          如果在程序中开启了事务,那么在应用程序发出提交/回滚请求后,数据库执行操作, 而后将成功/失败返回给应用程序,程序继续执行。
          一阶段提交协议相对简单。优点也很直观,它不用再与其他的对象交互,节省了判断 步骤和时间,所以在性能上是在阶段提交协议中最好的。但缺点也很明显:数据库确认执行 事务的时间较长,出问题的可能性就随之增大。如果有多个数据源,一阶段提交协议无法协 调他们之间的关系。
    注意:一阶段提交事务,不能解决分布式事务,只能用于单体架构项目。

    C)XA协议的二阶段提交 (好处:添加了一个管理者的角色)

    在这里插入图片描述
      二阶段协议通过将两层变为三层,增加了中间的管理者角色,从而协调多个数 据源之间的关系,二阶段提交协议分为两个阶段。
    在这里插入图片描述
      应用程序调用了事务管理器的提交方法,此后第一阶段分为两个步骤:
      事务管理器通知参与该事务的各个资源管理器,通知他们开始准备事务。
      资源管理器接收到消息后开始准备阶段,写好事务日志并执行事务,但不提交,然后将 是否就绪的消息返回给事务管理器(此时已经将事务的大部分事情做完,以后的内容耗时极 小)。
    在这里插入图片描述
      第二阶段也分为两个步骤:
      事务管理器在接受各个消息后,开始分析,如果有任意其一失败,则发送回滚命令,否 则发送提交命令。
       各个资源管理器接收到命令后,执行(耗时很少),并将提交消息返回给事务管理器。 事务管理器接受消息后,事务结束,应用程序继续执行。
      为什么要分两步执行?一是因为分两步,就有了事务管理器统一管理的机会;二尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作,这样,最后的提交阶 段将是耗时极短,耗时极短意味着操作失败的可能性也就降低。
      同时,二阶段提交协议为了保证事务的一致性,不管是事务管理器还是各个资源管 理器,每执行一步操作,都会记录日志,为出现故障后的恢复准备依据。
    缺点:
      1 二阶段提交协议的存在的弊端是阻塞,因为事务管理器要收集各个资源管理器的响应 消息,如果其中一个或多个一直不返回消息,则事务管理器一直等待,应用程序也被阻塞, 甚至可能永久阻塞。
       2 两阶段提交理论的一个广泛工业应用是 XA 协议。目前几乎所有收费的商业数据库都 支持 XA 协议。XA 协议已在业界成熟运行数十年,但目前它在互联网海量流量的应用场景 中,吞吐量这个瓶颈变得十分致命,因此很少被用到

    2)TCC解决方案

    1)TCC介绍(开发量大)

    TCC 是由支付宝架构师提供的一种柔性解决分布式事务解决方案,主要包括三个步骤 (三个接口)
    Try:预留业务资源/数据效验
    Confirm:确认执行业务操作
    Cancel:取消执行业务操作
    在这里插入图片描述

    2) TCC原理

    与XA的区别:事务的管理者是以一个独立的服务出现,而不是中间件
      TCC 方案在电商、金融领域落地较多。TCC 方案其实是两阶段提交的一种改进。其 将整个业务逻辑的每个分支显式的分成了 Try、Confirm、Cancel 三个操作。Try 部分完成 业务的准备工作,confirm 部分完成业务的提交,cancel 部分完成事务的回滚。基本原理如 下图所示。

    在这里插入图片描述

    3)TCC 的关键流程如下图(以创建订单和扣减库存为例子)

    在这里插入图片描述

    4)TCC的优缺点

    **优点:**让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量称为可能。
    **缺点:**对应用的侵入性强。业务逻辑的每个分支都需要实现 try、confirm、cancel 三个操作,应用侵入性较强,改造成本高。 实现难度较大。需要按照网络状态、系统故障等不同的失败原因实现不同的 回滚策略。为了满足一致性的要求,confirm 和 cancel 接口必须实现幂等(多次操作时只执行一次操作)。

    3)分布式事务中间件解决方案

    分布式事务中间件其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性 的效果。典型代表有:阿里的 GTS(https://www.aliyun.com/aliware/txc)、开源应用 LCN。

    二、LCN分布式事务处理的框架介绍

    1.LCN(锁定事务单元(lock)、确认事务模块状态(confirm)、通知事务(notify))由来

    用来解决分布式事务。
    特点:不是数据库中间件产品,采用柔性事务机制,需要事务协调器

    2.LCN相关资料

    tx-lcn 官方地址:https://www.txlcn.org/
    tx-lcnGithub 地址:https://github.com/codingapi/tx-lcn
    tx-lcn 服务下载地址:https://pan.baidu.com/s/1cLKAeE#list/path=%2F
    tx-lcn 服务源码地址:https://github.com/codingapi/tx-lcn/tree/master/tx-manager

    3.LCN框架的原理及执行步骤

    1)LCN原理

    在这里插入图片描述

    2)LCN的执行步骤(重要)

    A) 创建事务组

    事务组:当前所涉及的所有事务的集合
    创建事务组是指在事务发起方开始执行业务代码之前先调用 TxManager 创建事务组 对象,然后拿到事务标示 GroupId 的过程。

    B) 添加事务组

    添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给 TxManager 的操作。

    C) 关闭事务组

    是指在发起方执行完业务代码以后,将发起方执行结果状态通知给 TxManager 的动 作。当执行完关闭事务组的方法以后,TxManager 将根据事务组信息来通知相应的参与模 块提交或回滚事务。

    D) 业务执行流程图

    在这里插入图片描述

    4.LCN的事务协调机制

    在这里插入图片描述
    提交的时候是提交给谁呢?
    是提交给了我们的 TxClient 模块。然后 TxCliient 模块下有一个连接池,就是框架自定 义的一个连接池(如图 DB 连接池);这个连接池其实就是在没有通知事务之前一直占有着 这次事务的连接资源,就是没有释放。但是他在切面里面执行了 close 方法。在执行 close 的时候。如果需要(TxManager)分布式事务框架的连接。他被叫做“假关闭”,也就是没有 关闭,只是在执行了一次关闭方法。实际的资源是没有释放的。这个资源是掌握在 LCN 的 连接池里的。
    当 TxManager 通知提交或事务回滚的时候呢?
    TxManager 会通知我们的 TxClient 端。然后 TxClient 会去执行相应的提交或回滚。提交 或回滚之后再去关闭连接。这就是 LCN 的事务协调机制。说白了就是代理 DataSource 的机 制;相当于是拦截了一下连接池,控制了连接池的事务提交。

    5. LCN的事务补偿机制

    1)什么是事务补偿机制

    LCN 的补偿事务原理是模拟上次失败事务的请求,然后传递给 TxClient 模块然后再次 执行该次请求事务。
    简单的说:lcn 事务补偿是指在服务挂机和网络抖动情况下 txManager 无法通知事务单 元时。(通知不到也就两种原因服务挂了和网络出问题)在这种情况下 TxManager 会做一 个标示;然后返回给发起方。告诉他本次事务有存在没有通知到的情况。
    那么如果是接收到这个信息之后呢,发起方就会做一个标示,标示本次事务是需要补偿 事务的。这就是事务补偿机制。

    2) 为什么需要事务补偿

    事务补偿是指在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或者网 络抖动等问题导致事务没有正常提交,此种场景就需要通过补偿来完成事务,从而达到事务 的一致性(2种情况,实时一致性:当前操作必须保证一致性;最终一致性:未提交成功,但是一段时间之后,在提交只要保证一致即可)。

    3) 补偿机制的触发条件

    当执行关闭事务组步骤时,若发起方接受到失败的状态后将会把该次事务识别为待补偿 事务,然后发起方将该次事务数据异步通知给 TxManager。TxManager 接受到补偿事务以后 先通知补偿回调地址,然后再根据是否开启自动补偿事务状态来补偿或保存该次切面事务数 据

    三、LCN分布式事务框架的应用

    1.案例设计

    1.1 需求

    创建三个服务分别为:springcloud-portal、springcloud-order、springcloud-inventory。在 springcloud-portal 服务中处理创建订单的请求,然后分别请求 springcloud-order 以及 springcloud-inventory服务。在springcloud-order中插入一条订单数据,在springcloud-inventory 中对商品的数量做更新。

    1.2 使用技术

    数据库:Mysql
    开发平台:SpringCloud+SpringBoot+MyBatis

    1.3 数据库设计

    创建两个数据库分别为: sxt_orders, sxt_inventory。 springcloud-order 操作 sxt_orders 库, springclooud-inventory 操作 sxt_inventory 库

    2. 创建服务

    2.1 创建项目

    2.1.1 springcloud-portal

    pom文件:
    application.properties配置文件

    2.1.2 springcloud-order

    pom文件:
    application.properties配置文件

    2.1.3 springcloud-inventory

    pom文件:
    application.properties配置文件

    展开全文
  • TX-LCN分布式事务

    2021-01-20 10:56:05
    目录1 分布式事务1.1 分布式事务是什么?1.2 什么时候使用分布式事务1.3 分布式事务常见解决方案1.3.1 基于 XA 协议两阶段提交1.3.2 消息事务+最终一致性2 分布式事务理论依据2.1 CAP 定理2.1.1 一致性(C)2.1.2 ...

    目录

    1 分布式事务

    1.1 分布式事务是什么?

    • 在分布式系统中,事务参与者在不同的分布式节点上事务操作的数据源不是同一个, 这些情况产生的事务都叫做分布式事务。
    • 例如:
      项目 A 实现 Tb_item 表新增、项目 B 实现 tb_item_param 新增,现在需要实现商品新增,需要把项目 A 和项目 B 两个项目新增的方法组成一个事务,这个事务就是分布式事务。
    • 例如:
      项目中向 MySQL 做新增,同时还需要向 Redis 或 MongoDB 执行新增,希望执行 MySQL 或 Redis 或 MongoDB 时如果出现异常进行事务回滚,这种情况也成为分布式事务。

    1.2 什么时候使用分布式事务

    • 事务的概念最早是在学习数据库(MySQL、Oracle)中接触到的,一个事务(本地事务)就是一系列 SQL 语句的集合,只要在执行过程中一条 SQL 出错就会导致整个事务失败,回滚到原点。而在分布式系统中存在多模块完成一次业务。那么就存在一个业务由多模块操作同一个数据源
      设置
    • 甚至可能存在一个业务横跨多种数据源节点的可能。这些问题都可以由分布式事务解决方案 TX-LCN 解决

    在这里插入图片描述

    1.3 分布式事务常见解决方案

    1.3.1 基于 XA 协议的两阶段提交

    • 分布式事务通常采用 2PC 协议,全称 Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过 2PC 协议将提交分成两个阶段:
      1.prepare
      2.commit/rollback
    • 阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者 ready 时,向 transaction manager 报告已准备就绪。
    • 阶段二为提交阶段(commit)。当 transaction manager 确认所有参与者都 ready 后,向所有参与者发送 commit 命令

    1.3.2 消息事务+最终一致性

    • 所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操作成功并且对外发消息成功,要么两者都失败
    • 分布式事务,本质上是对多个数据库的事务进行统一控制,按照控制力度可以分为:不控制、部分控制和完全控制。不控制就是不引入分布式事务,部分控制就是各种变种的两阶段提交,包括上面提到的消息事务+最终一致性、TCC 模式,而完全控制就是完全实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数 据一致性减弱了,完全控制则是牺牲了性能,保障了一致性,具体用哪种方式,最终还是取决于业务场景

    2 分布式事务理论依据

    • 分布式事务存在两大理论依据:CAP 定理和 BASE 理论

    2.1 CAP 定理

    • CAP 定理是指在一个分布式系统中 Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),最多同时满足其中两个,三者不可兼得。

    2.1.1 一致性(C)

    • 在分布式系统中所有节点的状态是一样的。

    2.1.2 可用性(A)

    • 在集群中一部分节点出现故障后,整个集群是否还能响应客户端请求。

    2.1.3 分区容错性(P)

    • 以实际效果而言,分区相当于对操作的时限要求。如果系统不能在一定时限内达到数据一致性,就意味着发生了分区的情况,此时就必须在 A 和 C 中做选择。

    2.2 BASE 理论

    • 是指 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。
    • BASE 理论是对 CAP 中一致性和可用性权衡的结果,是基于 CAP 演化而来的。
    • BASE 理论核心思想:即使无法做到强一致性,每个应用都可以根据自身业务特点,采用适当的方式达到最终一致性

    2.2.1 基本可用(BA)

    • 是指在分布式系统中出现不可知故障的时候,允许损失部分可用性。此处要注意:损失部分可用性,不代表整个系统不可用
    • 例如:
      1.可以增加响应时间。由之前 0.5 秒,在出现故障的时候变成 1~2 秒
      2.由于一些特殊原因,使网站访问流量激增,为了保证整个系统的稳定性,部分访问者可能被引导到降级页面中

    2.2.2 软状态(S)

    • 是指系统中数据允许存在中间状态(软状态),并认为这个状态是不影响系统的可用性的。通俗解释:允许分布式节点之间存在同步延迟
    • 例如:
      在 Eureka 集群中数据同步时就存在软状态

    2.2.3 最终一致性

    • 允许整个系统中数据在经过一定时间后,最终能达到整个系统的一致性。但是这个时间绝对不可以过长
    • 强一致性要求系统接收请求后,整个系统必须达到一致性效果,才会响应结果
    • 最终一致性是弱一致性的特例。满足最终一致性的系统在响应给用户结果时整个系统可能是没有达到一致性的,但是最终一定会达到一致性效果的

    3 TX-LCN 概述

    3.1 简介

    • LCN 框架在 2017 年 6 月发布第一个版本
    • LCN 早期设计时,1.0 版本和 2.0 版本设计步骤如下:
      1.锁定事务单元(Lock)
      2.确认事务模块状态(Confirm)
      3.通知事务(Notify)
    • 取各自首字母后名称为 LCN。
    • LCN 框架从 5.0 开始兼容了 LCN、TCC、TXC 三种事务模式,为了和 LCN 框架区分,从 5.0 开始把 LCN 框架更名为:TX-LCN 分布式事务框架

    3.2 TX-LCN 原理

    • TX-LCN 由两大模块组成,TxClient、TxManager
    • TxClient 作为模块的依赖框架,提供了 TX-LCN 的标准支持,事务发起方和参与方都属于 TxClient。TxManager 作为分布式事务的控制方,控制整个事务

    在这里插入图片描述

    3.2.1 原理中核心内容

    3.2.1.1 创建事务组

    • 是指在事务发起方开始执行业务代码之前先调用 TxManager 创建事务组对象,然后拿到事务标识 GroupId 的过程。

    3.2.1.2 加入事务组

    • 添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给 TxManager 的操作。

    3.2.1.3 通知事务组

    • 是指在发起方执行完业务代码以后,将发起方执行结果状态通知给 TxManager,TxManager 将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方

    4 TX-LCN 事务模式

    • Tx-LCN 5.0 开始支持三种事务模式,分别是:LCN、TCC、TXC 模式。
    • 每种模式在实际使用时有着自己对应的注解。
    LCN:@LcnTransaction 
    TCC:@TccTransaction 
    TXC:@TxcTransaction
    123
    

    4.1 LCN 模式

    4.1.1 原理介绍

    • LCN 模式是通过代理 JDBC 中 Connection 的方式实现对本地事务的操作,然后在由TxManager 统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,该代 理的连接将由 LCN 连接池管理

    4.1.2 模式特点

    • 该模式对代码的嵌入性低。
    • 该模式仅限于本地存在连接对象且可通过连接对象控制事务的模块。
    • 该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障
    • 该模式缺陷在于代理的连接需要随事务发起方一同释放连接,增加了连接占用的时间
    • 总结:LCN 模式适合能用 JDBC 连接的所有支持事务的数据库

    4.2 TCC 事务模式

    4.2.1 原理介绍

    • TCC 事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对 XA 的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务

    4.2.2 代码说明

    • 每个 TCC 事务处理方法可以额外包含 confirmXxx 和 cancelXxx 的方法(),出现失败问题,需要在 cancel 中通过业务逻辑把改变的数据还原回来
    • confirmXxx 和 cancelXxx 两个方法会由 TxManager 进行统一协调调用
    • confirmXxx 和 cancelXxx 也可以在@TccTransaction 注解中通过属性明确指定
    @TccTransaction 
    public String demo(){ 
    	// 正常的 service 方法,也是 Try 尝试执行执行 
    }
    
    public void confirmDemo(){ 
    	// 当 demo 方法没有出现异常时执行的方法 
    	// 方法名称必须叫做 confirm+代理方法首字母 
    }
    
    public void cancelDemo(){ 
    	// 当 demo 方法出现异常时执行的方法 
    	// 方法名称必须叫做 cancel+代理方法首字母 
    }
    

    4.2.3 模式特点

    • 该模式对代码的嵌入性高,要求每个业务需要写二个以上步骤的操作
    • 该模式对有无本地事务控制都可以支持,使用面更广
    • 数据一致性控制几乎完全由开发者控制,对业务开发难度要求高
    • 总结:Tcc 模式应用于所有不支持 XA 事务的软件。例如:redis,mongodb 等

    4.3 TXC 事务模式

    4.3.1 原理介绍

    • TXC 模式命名来源于淘宝,实现原理是在执行 SQL 之前,先查询 SQL 的影响数据,然后保存执行的 SQL 信息和创建锁。当需要回滚的时候就采用这些记录数据回滚数据库,目前锁实现依赖 redis 分布式锁控制。(在使用 lcn 时必须要配置 redis 参数)

    4.3.2 模式特点

    • 该模式同样对代码的嵌入性低
    • 该模式仅限于对支持 SQL 方式的模块支持
    • 该模式由于每次执行 SQL 之前需要先查询影响数据,因此相比 LCN 模式消耗资源与时间要多
    • 该模式不会占用数据库的连接资源
    • 总结:只能用在支持 SQL 的数据库。对资源消耗较多。建议使用 LCN 模式

    5 XA 的两阶段提交方案(数据库支持分布式事务,为什么还用 TX-LCN)

    5.1 什么是 XA 协议

    • XA 协议由 Oracle Tuxedo 首先提出的,并交给 X/Open 组织,作为资源管理器(数据库)与事务管理器的接口标准。目前,Oracle、Informix、DB2 和 Sybase 等各大数据库厂家都提供对 XA 的支持。XA 协议采用两阶段提交方式来管理分布式事务。XA 接口提供资源管理器与事务管理器之间进行通信的标准接口。
    • XA 就是 X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA 接口函数由数据库厂商提供。
    • X/Open 组织(即现在的 Open Group)定义了分布式事务处理模型。X/Open DTP 模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。一般,常见的事务管理器(TM)是交易中间件,常见的资源管理器(RM)是数据库,常见的通信资源管理器(CRM)是消息中间件。

    5.2 XA 协议的一阶段提交

    在这里插入图片描述

    • 如果在程序中开启了事务,那么在应用程序发出提交/回滚请求后,数据库执行操作,而后将成功/失败返回给应用程序,程序继续执行
    • 一阶段提交协议相对简单。优点也很直观,它不用再与其他的对象交互,节省了判断步骤和时间,所以在性能上是在阶段提交协议中最好的。但缺点也很明显:数据库确认执行事务的时间较长,出问题的可能性就随之增大。如果有多个数据源,一阶段提交协议无法协调他们之间的关系

    5.3 XA 协议的二阶段提交

    • 在一阶段协议的基础上,有了二阶段协议,二阶段协议的好处是添加了一个管理者角色
      在这里插入图片描述

    • 很明显,二阶段协议通过将两层变为三层,增加了中间的管理者角色,从而协调多个数据源之间的关系,二阶段提交协议分为两个阶段
      在这里插入图片描述

      应用程序调用了事务管理器的提交方法,此后第一阶段分为两个步骤:

    • 事务管理器通知参与该事务的各个资源管理器,通知他们开始准备事务。

    • 资源管理器接收到消息后开始准备阶段,写好事务日志并执行事务,但不提交,然后将是否就绪的消息返回给事务管理器(此时已经将事务的大部分事情做完,以后的内容耗时极小)。
      在这里插入图片描述

      第二阶段也分为两个步骤:

    • 事务管理器在接受各个消息后,开始分析,如果有任意其一失败,则发送回滚命令,否则发送提交命令

    • 各个资源管理器接收到命令后,执行(耗时很少),并将提交消息返回给事务管理器

    • 事务管理器接受消息后,事务结束,应用程序继续执行

    • 为什么要分两步执行?一是因为分两步,就有了事务管理器统一管理的机会;二尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作,这样,最后的提交阶段将是耗时极短,耗时极短意味着操作失败的可能性也就降低

    • 同时,二阶段提交协议为了保证事务的一致性,不管是事务管理器还是各个资源管理器,每执行一步操作,都会记录日志,为出现故障后的恢复准备依据


    缺点:

    • 二阶段提交协议的存在的弊端是阻塞,因为事务管理器要收集各个资源管理器的响应消息,如果其中一个或多个一直不返回消息,则事务管理器一直等待,应用程序也被阻塞,甚至可能永久阻塞
    • 两阶段提交理论的一个广泛工业应用是 XA 协议。目前几乎所有收费的商业数据库都支持 XA 协议。XA 协议已在业界成熟运行数十年,但目前它在互联网海量流量的应用场景中,吞吐量这个瓶颈变得十分致命,因此很少被用到

    6 TxManager 搭建

    6.1 创建项目,添加依赖

    • 新建项目 TxManager,并添加依赖
    • 依赖包含了 Spring-boot 的依赖,版本是 2.0.5,如果希望把版本改变成 2.2.2 或其他版本只需要添加 spring-boot-starter-parent 继承即可
    <dependencies> 
    	<dependency> 
    		<groupId>com.codingapi.txlcn</groupId> 
    		<artifactId>txlcn-tm</artifactId> 
    		<version>5.0.2.RELEASE</version> 
    	</dependency> 
    </dependencies>
    

    6.2 执行 SQL 文件

    • 执行 tx-manager.sql 文件(在任意的数据库下执行即可)
    • tx-manager.sql 在 txlcn-tm-5.0.2.RELEASE.zip 压缩包中。
    • 在 MySQL 生成 tx-manager 的数据库,在数据库中新建 t_tx_exception 的表,此表用作存储事务组信息
    • 注意:
    • 默认情况下 tx-manager 需要记录日志信息的,需要在项目中配置日志连接数据库相关参数,其中日志存储数据库没有要求,可以存储到任意数据库中,当运行后会自动在数据库中生成一个日志表。如果不希望记录日志可以直接设置 tx-lcn.logger.enabled=false,关闭日志功能,下面的日志连接数据库参数也可以不用配置。
    • 在实际案例演示中会把所有的日志记录功能关闭。如果希望记录记录日志需要把下面代码在所有引用 tx-lcn 的项目的配置文件中进行配置
    tx-lcn.logger.enabled=true 
    tx-lcn.logger.driver-class-name=com.mysql.jdbc.Driver 
    tx-lcn.logger.jdbc-url=jdbc:mysql://192.168.8.131:3306/tx-manager?characterEncoding=UTF-8 
    tx-lcn.logger.username=root 
    tx-lcn.logger.password=root
    

    6.3 配置配置文件

    • 在 TxManager 项目的 resource 下新建 application.properties。tx-lcn 在当前版本有个 bug 只能使用 properties 文件,使用 yml 文件会导致配置文件无法被加载的问题
    • 配置文件中内容上半部分是 tx-manager 数据库的连接信息。中间包含 redis 连接信息(此处连接的是 redis 单机版,端口默认,没有密码),下面是关闭日志记录功能
    • 小提示:
    • 依赖 Redis,所以需要安装 Redis。
    • 7970 是客户端访问端口,是 Txmanager 可视化界面访问端口,此端口任意。
    spring.application.name=TransactionManager
    server.port=7970
    
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=root
    spring.redis.host=192.168.8.129
    
    tx-lcn.logger.enabled=false
    

    6.4 新建启动类

    • 注意注解@EnableTrasactionManagerServer 必须有
    @SpringBootApplication 
    @EnableTransactionManagerServer
    public class MyApplication { 
    	public static void main(String[] args) { 
    		SpringApplication.run(MyApplication.class,args); 
    	} 
    }
    

    6.5 访问管理界面

    • 在浏览器输入:http://localhost:7970 访问。
    • 密码默认是 codingapi
    • 可以在配置文件中修改登录密码
    tx-lcn.manager.admin-key=dqcgm
    

    在这里插入图片描述

    7 LCN 事务模式

    7.1 创建数据库表

    • 注意:不要给 student 表添加外键约束。如果添加会导致分布式事务执行时 student 新增失败,因为 teacher 没有提交时 student 的 tid 值无法获取。
      设置

    7.2 创建项目

    • 案例使用聚合项目进行演示。
    • 创建父项目,名称为 LcnParent

    7.2.1 配置 pom.xml

    • txlcn-tc 是 TX-LCN 的客户端包
    • txlcn-txmsg-netty 是 LCN 客户端连接 TxManager 需要的包
    <parent>
    	<groupId>org.springframework.boot</groupId> 
    	<artifactId>spring-boot-starter-parent</artifactId> 
    	<version>2.2.6.RELEASE</version>
    </parent>
    <dependencies>
    	<dependency> 
    		<groupId>org.springframework.boot</groupId> 
    		<artifactId>spring-boot-starter-web</artifactId> 
    	</dependency>
    	<dependency> 
    		<groupId>org.mybatis.spring.boot</groupId> 
    		<artifactId>mybatis-spring-boot-starter</artifactId> 
    		<version>2.1.2</version> 
    	</dependency>
    	<dependency> 
    		<groupId>org.springframework.cloud</groupId> 
    		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 
    	</dependency>
    	<dependency> 
    		<groupId>org.springframework.cloud</groupId> 
    		<artifactId>spring-cloud-starter-openfeign</artifactId> 
    	</dependency>
    
    	<dependency> 
    		<groupId>mysql</groupId> 
    		<artifactId>mysql-connector-java</artifactId> 
    		<version>5.1.48</version> 
    		<scope>runtime</scope> 
    	</dependency>
    	<dependency> 
    		<groupId>org.projectlombok</groupId> 
    		<artifactId>lombok</artifactId> 
    		<optional>true</optional> 
    	</dependency>
    	<dependency> 
    		<groupId>com.codingapi.txlcn</groupId> 
    		<artifactId>txlcn-tc</artifactId> 
    		<version>5.0.2.RELEASE</version> 
    	</dependency>
    	<dependency> 
    		<groupId>com.codingapi.txlcn</groupId> 
    		<artifactId>txlcn-txmsg-netty</artifactId> 
    		<version>5.0.2.RELEASE</version> 
    	</dependency>
    </dependencies>
    <dependencyManagement>
    	<dependencies> 
    		<dependency> 
    			<groupId>org.springframework.cloud</groupId> 
    			<artifactId>spring-cloud-dependencies</artifactId> 
    			<version>Hoxton.SR4</version> 
    			<type>pom</type> 
    			<scope>import</scope> 
    		</dependency> 
    	</dependencies> 
    </dependencyManagement>
    

    7.3 新建 pojo 项目

    • 把实体类提出来
    • 新建两个实体类。
    • 新建 com.dqcgm.pojo.Teacher
    @Data 
    public class Teacher { 
    	private Long id; 
    	private String name; 
    }
    12345
    
    • 新建 com.dqcgm.pojo.Student
    @Data 
    public class Student { 
    	private Long id; 
    	private String name; 
    	private Long tid; 
    }
    

    7.4 创建项目 teacher_insert

    • 新建 teacher_insert 项目

    7.4.1 配置 pom.xml

    • 依赖 pojo
    <dependencies> 
    	<dependency> 
    		<artifactId>pojo</artifactId> 
    		<groupId>com.dqcgm</groupId> 
    		<version>0.0.1-SNAPSHOT</version> 
    	</dependency> 
    </dependencies>
    

    7.4.2 编写配置文件

    • 新建 application.yml.
    • 数据源连接的是 Teacher 表所在数据库
    • eureka 单机版可以省略。
    • manager-address 配置 TxManager 项目的 ip 及端口。端口是内部访问端口,而不是可视化页面的端口
    spring: 
    	datasource:
    		url: jdbc:mysql://localhost:3306/microservice
    		driver-class-name: com.mysql.jdbc.Driver
    		username: root
    		password: root
    	application:
    		name: teacher-insert
    server: 
    	port: 8080
    
    eureka: 
    	client: 
    		service-url: 
    			defaultZone: http://localhost:8761/eureka/
    
    tx-lcn:
    	client: 
    		manager-address: 127.0.0.1:8070
    

    7.4.3 新建 mapper

    • 新建 com.dqcgm.mapper.TeacherMapper
    @Mapper 
    public interface TeacherMapper { 
    	@Insert("insert into teacher values(#{id},#{name})") 
    	int insert(Teacher teacher); 
    }
    12345
    

    7.4.4 新建 service 及实现类

    • 新建 com.dqcgm.service.TeacherService 及实现类。
    • 方法上@Transactional 一定要有。本地事务控制。
    • @LcnTransaction 表示当前方法加入到分布式事务控制。
    • @LcnTransaction 属性 propagation 可取值
      1.DTXPropagation.REQUIRED:默认值,表示如果当前没有事务组创建事务组,如果有事务组,加入事务组。多用在事务发起方。
      DTXPropagation.SUPPORTS:如果当前没有事务组以本地事务运行,如果当前有事务组加入事务组。多用在事务参与方法。
    public interface TeacherService { 
    	int insert(Teacher teacher); 
    }
    123
    @Service 
    public class TeacherServiceImpl implements TeacherService {
    	@Autowired
    	private TeacherMapper teacherMapper;
    
    	@Override 
    	@LcnTransaction 
    	@Transactional
    	public int insert(Teacher teacher) { 
    		return teacherMapper.insert(teacher); 
    	} 
    }
    

    7.4.5 新建控制器

    • 新建 com.dqcgm.controller.TeacherController。
    • 由于在 student_insert 中通过 OpenFeign 进行条件,参数使用请求体数据,所以控制器方法的参数需要添加@RequestBody
    @Controller 
    public class TeacherController {
    	@Autowired 
    	private TeacherService teacherService;
    
    	@RequestMapping("/insert") 
    	@ResponseBody
    	public int insert(@RequestBody Teacher teacher){ 
    		System.out.println("taecher"+teacher); 
    		return teacherService.insert(teacher); 
    	} 
    }
    

    7.4.6 新建启动器

    • 新建 com.dqcgm.TeacherInsertApplication。
    • 一定要有注解@EnableDistributedTransaction 表示启动分布式事务
    @SpringBootApplication 
    @EnableDistributedTransaction 
    public class TeacherInsertApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(TeacherInsertApplication.class,args); 
    	} 
    }
    

    7.5 新建项目 student_insert

    7.5.1 编写 pom.xml

    • 添加对 pojo 依赖
    <dependencies> 
    	<dependency> 
    		<artifactId>pojo</artifactId> 
    		<groupId>com.dqcgm</groupId> 
    		<version>0.0.1-SNAPSHOT</version> 
    	</dependency> 
    </dependencies>
    

    7.5.2 创建配置文件

    • 新建 application.yml
    spring: 
    	datasource:
    		url: jdbc:mysql://localhost:3306/microservice 
    		driver-class-name: com.mysql.jdbc.Driver 
    		username: root 
    		password: root
    	application:
    		name: student-insert
    server: 
    	port: 8081
    
    eureka: 
    	client: 
    		service-url: 
    			defaultZone: http://localhost:8761/eureka/
    
    tx-lcn: 
    	client:
    		manager-address: 127.0.0.1:8070
    

    7.5.3 新建 Feign 接口

    • 新建 com.dqcgm.feign.TeacherInsertFeign
    @FeignClient("teacher-insert") 
    public interface TeacherInsertFeign { 
    	@RequestMapping("/insert") int insert(Teacher teacher); 
    }
    

    7.5.4 新建 Mapper

    • 新建 com.dqcgm.mapper.StudentMapper
    @Mapper 
    public interface StudentMapper { 
    	@Insert("insert into student values(#{id},#{name},#{tid})") 
    	int insert(Student student); 
    }
    

    7.5.5 新建 service 及实现类

    • 新建 com.dqcgm.service.StudentService
    • 实现类中对 Teacher 和 Student 的主键都是随机数,为了测试时多次测试方便,所以没有给固定值
    • Student 的姓名通过客户端请求参数传递的,其他都不需要通过参数设置
    public interface StudentService { 
    	int insert(Student student); 
    }
    @Service 
    public class StudentServiceImpl implements StudentService {
    	@Autowired
    	private StudentMapper studentMapper;
    
    	@Autowired 
    	private TeacherInsertFeign teacherInsertFeign;
    
    	@Override 
    	@LcnTransaction 
    	@Transactional 
    	public int insert(Student student) {
    		Teacher teacher = new Teacher();
    		Random random = new Random();
    		teacher.setId((long)random.nextInt(10000));
    		teacher.setName("随意的名称");
    		student.setTid(teacher.getId());
    		student.setId((long)random.nextInt(10000));
    		teacherInsertFeign.insert(teacher);
    		return studentMapper.insert(student);
    	}
    }
    

    7.5.6 新建控制器

    • 新建 com.dqcgm.controller.StudentController
    @Controller 
    public class StudentController {
    	@Autowired 
    	private StudentService studentService;
    	
    	@RequestMapping("/insert") 
    	@ResponseBody 
    	public int insert(Student student){ 
    		return studentService.insert(student); 
    	} 
    }
    

    7.5.7 新建启动类

    • 新建 com.dqcgm.StudentInsertApplication
    @SpringBootApplication 
    @EnableDistributedTransaction 
    @EnableFeignClients 
    public class StudentInsertApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(StudentInsertApplication.class,args);
    	}
    }
    

    7.6 测试结果

    • 在浏览器中输入 http://localhost:8081/insert?name=dqcgm后,如果页面显示 1 并且数据库 teacher 表和 student 表各增加一条数据表示新增成功。
    • 为了测试分布式事务效果,在 student_insert 项目实现类方法 return 上面添加 int i =5/0; 的算术异常,再次访问 url 页面会报 500,并且数据库中没有新增数据,说明分布式事务成功了。
      在这里插入图片描述

    8 TCC 事务模式(多模式混合使用)

    • 在上面 LCN 事务模式代码基础上进行修改

    8.1 新建项目 mongodb_insert

    8.1.1 修改 pom.xml

    • 在当前项目中引入 mongodb 的依赖。如果在父项目中进行引入,则所有的子项目都需要配置 mongodb 的相关属性
    <dependencies> 
    	<dependency> 
    		<groupId>org.springframework.boot</groupId> 
    		<artifactId>spring-boot-starter-data-mongodb</artifactId> 
    		<version>2.2.6.RELEASE</version> 
    	</dependency> 
    </dependencies>
    

    8.1.2 新建配置文件

    • 新建 application.yml。
    • 虽然当前项目是连接 Mongodb 但是也需要配置 MySQL 数据源,因为 LCN 需要在 MySQL 中记录异常信息等
    • 配置文件中比别的项目多了 MongoDB 的配置
    spring: 
    	datasource:
    		url: jdbc:mysql://localhost:3306/microservice
    		driver-class-name: com.mysql.jdbc.Driver
    		username: root
    		password: root
    	application:
    		name: mongodb-insert
    	data:
    		mongodb:
    			authentication-database: admin
    			username: dqcgm
    			password: dqcgmpwd
    			database: lcn
    			host: 192.168.8.139
    			port: 27017
    server:
    	port: 8082
    
    eureka: 
    	client: 
    		service-url: 
    			defaultZone: http://localhost:8761/eureka/
    
    tx-lcn: 
    	client: 
    		manager-address: 127.0.0.1:8070
    

    8.1.3 新建实体类

    • 新建 com.dqcgm.pojo.People
    @Data 
    public class People { 
    	private String id; 
    	private String name; 
    }
    

    8.1.4 新建 service 及实现类

    • 新建 com.dqcgm.service.PeopleService 及实现类
    • 具有@TccTransaction 注解的方法有以下特性
      1.可以没有@Transactional
      2.如果整个分布式事务所有方法执行都没有异常,会回调名称为:confirm+方法名首字母大写的方法。insert 方法的回调方法叫做 confirmInsert()。同时方法参数也可以传递给回调方法
      3.只要整个分布式事务中有一个方法出现异常,会回调 cancel+方法名首字母大写的回调方法。需要在这个方法中编写事务回滚的业务。
    • @TccTransaction 注解属性说明:
      cancelMethod:明确指定失败的回调方法名
      confirmMethod:明确指定成功的回调方法名
    public interface PeopleService { 
    	int insert(People people); 
    }
    @Service 
    public class PeopleServiceImpl implements PeopleService {
    	@Autowired 
    	private MongoTemplate mongoTemplate;
    	@Override 
    	@TccTransaction
    	public int insert(People people) {
    		People result = mongoTemplate.insert(people);
    		if(result!=null){
    			return 1;
    		}
    		return 0;
    	}
    
    	public void cancelInsert(People people){ 
    		System.out.println("执行了 cancel 方法"+people); 
    		mongoTemplate.remove(people); 
    		System.out.println("所谓的事务回滚就是删除新增的数据"); 
    	}
    
    	public void confirmInsert(People people){ 
    		System.out.println("执行了 confirm 方法"+people); 
    	}
    }
    

    8.1.5 新建控制器

    • 新建 com.dqcgm.controller.PeopleController
    @Controller
    public class PeopleController {
    	@Autowired 
    	private PeopleService peopleService; 
    	@RequestMapping("/insert") 
    	@ResponseBody
    	public int insert(People people){ 
    		return peopleService.insert(people); 
    	} 
    }
    

    8.1.6 测试

    • 在浏览器输入 http://localhost:8082/insert?name=dqcgm观察 mongodb 中是否出现了 lcn 的 数据库,数据库中是否出现 People 的集合,people 集合中 name 属性值为 dqcgm

    8.2 修改 student_insert

    8.2.1 新建 feign 接口

    • 新建 com.dqcgm.feign.MongodbInsertFeign。
    • 为了传递普通表单数据,insert 方法参数由@RequestParam。mongodb_insert 控制器方法参数就可以使用 String name 或 People 进行接收
    @FeignClient("mongodb-insert") 
    public interface MongodbInsertFeign { 
    	@RequestMapping("/insert") 
    	int insert(@RequestParam String name); 
    }
    

    8.2.2 修改 service 实现类

    • 修改 com.dqcgm.service.impl.StudentServiceImpl。
    • 在实现类中调用 feign 接口的方法
    • 当前方法依然使用 LCN 事务模式。方法上面加什么事务模式注解只考虑当前方法本地事务,不考虑调用远程方法的事务。如果当前方法中没有本地事务,全是调用远程方法,那么当前方法使用 LCN 或 TCC 事务模式都可以,但是必须要有事务模式,因为如果没有注解就不会想 TxManager 中创建事务组。
    @Service 
    public class StudentServiceImpl implements StudentService {
    	@Autowired 
    	private StudentMapper studentMapper; 
    	@Autowired 
    	private TeacherInsertFeign teacherInsertFeign;
    	@Autowired 
    	private MongodbInsertFeign mongodbInsertFeign; 
    	@Override 
    	@LcnTransaction 
    	@Transactional 
    	public int insert(Student student) {
    		Teacher teacher = new Teacher();
    		Random random = new Random();
    		teacher.setId((long)random.nextInt(10000));
    		teacher.setName("随意的名称");
    		student.setTid(teacher.getId());
    		student.setId((long)random.nextInt(10000));
    		teacherInsertFeign.insert(teacher);
    		mongodbInsertFeign.insert("随意的名称");
    		return studentMapper.insert(student);
    	}
    }
    
    展开全文
  • TX-LCN 分布式事务框架(Spring Cloud 高级)一、 什么分布式事务 分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。举个栗子: 电商系统中的...

    b74f6252646b08875199e76b4abb4bae.png

    TX-LCN 分布式事务框架

    (Spring Cloud 高级)

    一、 什么是分布式事务

    分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

    举个栗子:

    电商系统中的订单系统与库存系统

    5593aeeb3fb4536d2d9c6522b9adc037.png

    图中包含了库存和订单两个独立的微服务,每个微服务维护了自己的数据库。在交易系统的业务逻辑中,一个商品在下单之前需要先调用库存服务,进行扣除库存,再调用订单服务,创建订单记录。

    5de0ac6af3c5cde35a8aa71aac4a7850.png

    正常情况下,两个数据库各自更新成功,两边数据维持着一致性。

    如果在非正常情况下,有可能库存的扣减完成了,随后的订单记录却因为某些原因插入失败。或者是订单创建成功了,但是库存扣除商品的数据量失败了,这个时候,两边数据去了应有的一致性。

    a34ee4ad7ccf64407f406f28ac9606f5.png

    这时候就需要保证事务的一致性了,单数据源的用单机事务来保证。多数据源就需要依赖分布式事务来处理。

    二、 XA 的两阶段提交方案

    1 什么是 XA 协议

    XA 协议由 Oracle Tuxedo 首先提出的,并交给 X/Open 组织,作为资源管理器(数据库)与事务管理器的接口标准。目前,Oracle、Informix、DB2 和 Sybase 等各大数据库厂家都提供对 XA 的支持。XA 协议采用两阶段提交方式来管理分布式事务。XA 接口提供资源管理器与事务管理器之间进行通信的标准接口。

    XA 就是 X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA 接口函数由数据库厂商提供。

    X/Open 组织(即现在的 Open Group)定义了分布式事务处理模型。X/Open DTP 模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。一般,常见的事务管理器(TM)是交易中间件,常见的资源管理(RM)是数据库,常见的通信资源管理器(CRM)是消息中间件。

    2 XA 协议的一阶段提交

    9f1ca9f3cc86c91a3ff8cb6bdfe32571.png

    如果在程序中开启了事务,那么在应用程序发出提交/回滚请求后,数据库执行操作,

    而后将成功/失败返回给应用程序,程序继续执行。

    一阶段提交协议相对简单。优点也很直观,它不用再与其他的对象交互,节省了判断步骤和时间,所以在性能上是在阶段提交协议中最好的。但缺点也很明显:数据库确认执行事务的时间较长,出问题的可能性就随之增大。如果有多个数据源,一阶段提交协议无法协调他们之间的关系。

    3 XA 协议的二阶段提交

    在一阶段协议的基础上,有了二阶段协议,二阶段协议的好处是添加了一个管理者角色。

    957892ded39f652ce32697f5a2780a0b.png

    很明显,二阶段协议通过将两层变为三层,增加了中间的管理者角色,从而协调多个数据源之间的关系,二阶段提交协议分为两个阶段。

    233c48c92630ed0dc95ddcc5ae8cd450.png

    应用程序调用了事务管理器的提交方法,此后第一阶段分为两个步骤:

    事务管理器通知参与该事务的各个资源管理器(数据库),通知他们开始准备事务。资源管理器接收到消息后开始准备阶段,写好事务日志并执行事务,但不提交,然后将是否就绪的消息返回给事务管理器(此时已经将事务的大部分事情做完,以后的内容耗时极小)。

    43a76658f044f4079d3404deacd97c9d.png

    第二阶段也分为两个步骤:

    事务管理器在接受各个消息后,开始分析,如果有任意其一失败,则发送回滚命令,否则发送提交命令。

    各个资源管理器接收到命令后,执行(耗时很少),并将提交消息返回给事务管理器。

    事务管理器接受消息后,事务结束,应用程序继续执行。

    为什么要分两步执行?一是因为分两步,就有了事务管理器统一管理的机会;二尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作,这样,最后的提交阶段将是耗时极短,耗时极短意味着操作失败的可能性也就降低。

    同时,二阶段提交协议为了保证事务的一致性,不管是事务管理器还是各个资源管理器,每执行一步操作,都会记录日志,为出现故障后的恢复准备依据。

    缺点:

    1 二阶段提交协议的存在的弊端是阻塞,因为事务管理器要收集各个资源管理器的响应消息,如果其中一个或多个一直不返回消息,则事务管理器一直等待,应用程序也被阻塞,甚至可能永久阻塞。

    2 两阶段提交理论的一个广泛工业应用是 XA 协议。目前几乎所有收费的商业数据库都支持 XA 协议。XA 协议已在业界成熟运行数十年,但目前它在互联网海量流量的应用场景中,吞吐量这个瓶颈变得十分致命,因此很少被用到

    三、 TCC 解决方案

    1 TCC 介绍

    TCC 是由支付宝架构师提供的一种柔性解决分布式事务解决方案,主要包括三个步骤

    Try:预留业务资源/数据效验

    Confirm:确认执行业务操作

    Cancel:取消执行业务操作

    5ee79599506f136bd1411c0968bffdfa.png

    2 TCC 原理

    TCC 方案在电商、金融领域落地较多。TCC 方案其实是两阶段提交的一种改进。其将整个业务逻辑的每个分支显式的分成了 Try、Confirm、Cancel 三个操作。Try 部分完成业务的准备工作,confirm 部分完成业务的提交,cancel 部分完成事务的回滚。基本原理如下图所示。

    dcf1af43332588e9b6ee62204141ada3.png

    事务开始时,业务应用会向事务协调器注册启动事务。之后业务应用会调用所有服务的 try 接口,完成一阶段准备。之后事务协调器会根据 try 接口返回情况,决定调用 confirm接口或者 cancel 接口。如果接口调用失败,会进行重试。

    微服务倡导服务的轻量化、易部署,而 TCC 方案中很多事务的处理逻辑需要应用自己编码实现,复杂且开发量大

    3 TCC 的关键流程如下图(以创建订单和扣减库存为例子)

    下图中的TCC就是上图说的事务协调器

    7c2956e5f1ff119e698b0db3bc239621.png

    4 TCC 优缺点

    4.1TCC 优点:

    让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。

    4.2TCC 不足之处:

    对应用的侵入性强。业务逻辑的每个分支都需要实现 try、confirm、cancel三个操作,应用侵入性较强,改造成本高。

    实现难度较大。需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。为了满足一致性的要求,confirm 和 cancel 接口必须实现幂等。

    四、 分布式事务中间件解决方案

    分布式事务中间件其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果。典型代表有:阿里的 GTS(就是TCC的云部署版本)(https://www.aliyun.com/aliware/txc)、开源应用 LCN。

    其实现原理如下:

    d73ed5cee1b109fcbd0cdb6d8fa19687.png

    五、 什么是 LCN 框架

    1 LCN 框架的由来

    LCN 并不生产事务,LCN 只是本地事务的协调工

    在设计框架之初的 1.0 ~ 2.0 的版本时,框架设计的步骤是如下的,各取其首字母得来的 LCN 命名。

    锁定事务单元(lock)、确认事务模块状态(confirm)、通知事务(notify)

    2 LCN 框架相关资料

    tx-lcn 官方地址:https://www.txlcn.org/

    tx-lcn Github 地址:https://github.com/codingapi/tx-lcn

    tx-lcn 服务下载地址:https://pan.baidu.com/s/1cLKAeE#list/path=%2F

    tx-lcn 服务源码地址:https://github.com/codingapi/tx-lcn/tree/master/tx-manager

    六、 LCN 框架原理及执行步骤

    1 LCN 的执行原理

    1.1LCN 原理

    524f39f82b66063fbc9860b466d039ce.png

    在上图中,微服务 A,微服务 B,TxManager 事务协调器,都需要去 Eureka 中注册服务。Eureka 是用于 TxManager 与其他服务之间的相互服务发现。redis 是用于存放我们事务组的信息以及补偿的信息。然后微服务 A 与微服务 B 他们都需要去配置上我们 TxClient(这个表示这个服务是受TX-Manager控制的) 的包架构(代码的包架构);来支持我们的 LCN 框架,以及他们的数据库。

    2 LCN 执行步骤

    2.1创建事务组:

    事务组是指的我们在整个事务过程中把各个节点(微服务)单元的事务信息存储在一个固定单元里。但这个信息并不是代表是事务信息,而是只是作为一个模块的标示信息。

    创建事务组是指在事务发起方开始执行业务代码之前先调用 TxManager 创建事务组对象,然后拿到事务标示 GroupId 的过程。

    简单来说:我们服务当中,当去完成一个业务时,这个业务会涉及很多服务,不同的服务操作不同的数据库,那么LCN他会将所有的在这一次业务当中参加的事务添加到事务组中,对这些事务进行集中式的控制。

    所以这个事务组的作用就是用来表示当前在这一个业务当中所涉及到的所有的事务的集合

    2.2添加事务组:

    添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给TxManager 的操作。

    2.3关闭事务组:

    是指在发起方执行完业务代码以后,将发起方执行结果状态通知给 TxManager 的动作。当执行完关闭事务组的方法以后,TxManager 将根据事务组信息来通知相应的参与模块提交或回滚事务。

    2.4业务执行流程图

    45c87c2abf2881829aceb01f0b70157f.png

    七、 什么是 LCN 的事务协调机制

    0a52f0c03dc97759fba47f983bf4b988.png

    如图:假设服务已经执行到关闭事务组的过程,那么接下来作为一个模块执行通知给TxManager,然后告诉他本次事务已经完成。那么如图中 Txmanager 下一个动作就是通过事

    务组的 id,获取到本次事务组的事务信息;然后查看一下对应有那几个模块参与,然后如果是有 A/B/C 三个模块;那么对应的对三个模块做通知、提交、回滚。

    那么提交的时候是提交给谁呢?

    是提交给了我们的 TxClient 模块。然后 TxCliient 模块下有一个连接池,就是框架自定义的一个连接池(如图 DB 连接池);这个连接池其实就是在没有通知事务之前一直占有着这次事务的连接资源,就是没有释放。但是他在切面里面执行了 close 方法。在执行 close的时候。如果需要(TxManager)分布式事务框架的连接。他被叫做“假关闭”,也就是没有关闭,只是在执行了一次关闭方法。实际的资源是没有释放的。这个资源是掌握在 LCN 的连接池里的。

    然后当 TxManager 通知提交或事务回滚的时候呢?

    TxManager 会通知我们的 TxClient 端。然后 TxClient 会去执行相应的提交或回滚。提交或回滚之后再去关闭连接。这就是 LCN 的事务协调机制。说白了就是代理 DataSource 的机制;相当于是拦截了一下连接池,控制了连接池的事务提交。

    八、 什么是 LCN 的事务补偿机制

    1 什么是补偿事务机制?

    LCN 的补偿事务原理是模拟上次失败事务的请求,然后传递给 TxClient 模块然后再次执行该次请求事务。

    简单的说:lcn 事务补偿是指在服务挂机和网络抖动情况下 txManager 无法通知事务单元时。(通知不到也就两种原因服务挂了和网络出问题)在这种情况下 TxManager 会做一个标示;然后返回给发起方。告诉他本次事务有存在没有通知到的情况。

    那么如果是接收到这个信息之后呢,发起方就会做一个标示,标示本次事务是需要补偿事务的。这就是事务补偿机制。

    2 为什么需要事务补偿?

    事务补偿是指在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或者网络抖动等问题导致事务没有正常提交,此种场景就需要通过补偿来完成事务,从而达到事务的一致性。

    3 补偿机制的触发条件?

    当执行关闭事务组步骤时,若发起方接受到失败的状态后将会把该次事务识别为待补偿事务,然后发起方将该次事务数据异步通知给 TxManager。TxManager 接受到补偿事务以后先通知补偿回调地址,然后再根据是否开启自动补偿事务状态来补偿或保存该次切面事务数据。

    展开全文
  • 什么是事务? 事务(Transaction),一般是指要做或所做事情。在计算机术语是指访问并可能更新数据库各种数据项一个程序执行单元(unit)。事务通常由高级数据库操纵...假设你已经清楚知道了事务是什么

    什么是事务?

    事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成


    假设你已经清楚的知道了事务是什么,但是还是不太明白事务在分布式系统中的作用

    那分布式事务是用来做什么的呢?

    一般是为了解决类似以下的一些问题:

    1. 最经典的跨行转账,无论成功还是失败,网络异常还是金钱异常账户异常,用户的钱始终只能保持在一个数值(仅争对自己的账户 和自己的另一个银行账户转账)
    2. 用户秒杀商品成功,领取的时候却被告知商品已经没有了
    3. 用户注册到了一个集团公司的账户体系下,但是登陆某些app的时候却被告知用户不存在,但是重新注册的时候却又提示用户已经存在

    在我们java开发中,一般是基于sping cloud来进行开发,事务也是基于spring的spring-tx,事务一般只存在于本地事务,如果事务在两个模块,多个模块,甚至包含了其他公司等等情况,则无效

    1. 下单的时候要先扣库存,然后同时下订单,但是用户超时未支付(30min),所以需要取消订单并且回退库存,不过这种一般叫做长事务,会选择数据库持久化订单状态来解决,更长的事务甚至会超过一周一个月甚至一年
    2. 写入数据库的同时也写入redis,但是都写入成功以后又发生了异常,这个时候需要同时回滚redis和mysql,spring的本地事务的TranscantionManager冲突导致的只能mysql事务管理器生效或者redis事务管理器生效,一旦冲突就意味着只有一个能回滚
    3. 对接其他公司的事务

    因此,我们需要引入分布式事务


    我们项目使用了LCN分布式事务的总线控制方案

    启动服务后将服务注册到LCN的transcationManager服务器,简称tm服务,而注册到tm的TransactionClient服务,简称tc

    使用前我假设你已经知道tm服务是什么,并且启动了我们的tx-manager服务[LCN的transcationManager],接下来你该做的事情就是尽情使用了


    step1. 引入pom依赖

            <dependency>
                <groupId>com.codingapi.txlcn</groupId>
                <artifactId>txlcn-tc</artifactId>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>com.codingapi.txlcn</groupId>
                <artifactId>txlcn-txmsg-netty</artifactId>
                <scope>compile</scope>
            </dependency>
    

    step2. 加入配置文件

    tx-lcn:
      client:
      	#这里本来不应该为空,但是我已经为lcn适配了eureka,启动的时候会去eureka拉取lcn的tm服务器列表,不需要再手动填充lcn的tm服务器列表
        manager-address:
      logger:
        enabled: true
    

    step3. 使用@LcnTransaction和@Transactional,以下是伪代码:

    @RestContorller
    public class TestController{
    	private TestService testService;
    
    	@LcnTransaction
    	@Transactional
    	@GetMapping
        public Result<String> testFunction(){
        	int i = testService.doSomeThing();
        	return Result.success();
    	}
    }
    
    public interface TestService {
    	int doSomeThing();
    }
    
    @Service
    public class TestServiceImpl implements TestService {
    	private KafkaTemplate<Object,Object> kafkaTemplate;
    	private TestMessageMapper testMessageMapper;
    	private TestClient testClient;
    
        @LcnTransaction
        @Transactional
        @Override
    	int doSomeThing(){
    	    //发送kafka消息
    		kafkaTemplate.send(Topic,Key,Value);
            //写入数据库
    		testMessageMapper.sned(Message);
    		//远程调用,远程模块写入数据库
    		testClient.sendRemoteMessage(Message);
    		return 1;
    	}
    }
    }
    

    使用的话也就以上三步,同一个事务里可以插入数据库,还可以发送kafka消息,也可以远程调用由远程服务器来插入数据库


    注意: 一但发生异常,kafka发送的消息会回滚,插入数据库的数据也会回归,调用远程服务插入到远程服务器里的数据也会回滚[实际上这样说不严谨,分布式事务的原理就是当每一方都提交到事务里并且没有异常的时候再统一提交事务,然后持久化事务,一旦发生异常就回滚全部事务]

    展开全文
  • 最近笔者在面试过程发现,分布式... 那在这里就先要理解一下,什么是分布式事务管理,在单系统,事务管理想必大家都很清楚,举个栗子,银行转账过程,张三余额有100元,李四0元,张三要转50元给李四...
  • 一、 什么分布式事务 分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位 于不同的分布式系统的不同节点之上。 举个栗子: 电商系统中的订单系统与库存系统 图中包含了库存和...
  • 一、 什么分布式事务分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位 于不同的分布式系统的不同节点之上。 举个栗子: 电商系统中的订单系统与库存系统图中包含了库存和订单两个...
  • 分布式事务LCN使用-01

    2020-07-13 14:08:00
     LCN分布式事务系统通过代理数据资源,通TxManager(事务管理器)协调来完成对事务统⼀控制,这样操控⽅式使得框架对业务嵌⼊性⾮常低,在对本地代理资源同时也通过排它锁防⽌其他⼈ 访问,从⽽也保障了事务...
  • 1. LCN框架原理及执行步骤(1) LCN框架执行原理是什么?在上图,微服务 A,微服务 B,TxManager 事务协调器,都需要去 Eureka 注册服务。Eureka 是用于 TxManager 与其他服务之间相互服务发现。redis 是用于...
  • 一、 什么分布式事务分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位 于不同的分布式系统的不同节点之上。 举个栗子: 电商系统中的订单系统与库存系统图中包含了库存和订单两个...
  • 分布式事务学习-LCN

    2019-07-22 16:58:43
    1、什么分布式事务? 分布式事务是指事务参与者、支持事务服务器、资源服务器以及事务管理器分别位 于不同分布式系统不同节点之上。 图包含了库存和订单两个独立微服务,每个微服务维护了自己...
  • 1. 什么情况下需要使用分布式事务? 使用场景很多,先举一个常见:在微服务系统,如果一个业务需要使用到不同微服务,并且不同微服务对应不同数据库。 打个比方:电商平台有一个客户下订单业务逻辑...
  • 在分布式系统,事务参与者在不同的分布式节点上或事务操作的数据源不是同一个, 这些情况产生的事务都叫做分布式事务。 例如: 项目 A 实现 Tb_item 表新增、项目 B 实现 tb_item_param 新增,现在需要实现商品...
  • 事物特性(ACID)原子性(A)所谓的原子性就是说,在整个事务中的所有操作,要么全部完成,要么全部不做,没有中间状态。对于事务在执行中发生错误,所有的操作都会被回滚,整个事务就像从没被执行过一样。一致性(C)...
  • 什么情况下需要使用分布式事务? 使用场景很多,先举一个常见:在微服务系统,如果一个业务需要使用到不同微服务,并且不同微服务对应不同数据库。 打个比方:电商平台有一个客户下订单业务逻辑,这...
  • 前言这篇文章将给大家介绍一下对分布式事务的一些见解,并讲解分布式事务处理框架 TX-LCN 执行原理,错误之处望各位不吝指正。1. 什么情况下需要使用分布式事务?使用场景很多,先举一个常见:在微服务系统...
  • 在微服务系统分布式事务一直痛点,也难点。社区里也有一些开源分布式解决方案框架,比如ByteTCC、LCN,但是这些框架没有一个权威组织在维护,或多或少大家都有点不敢用。阿里开源的分布式事务解决框架...
  • 这篇文章将给大家介绍一下对分布式事务的一些见解,并讲解分布式事务处理框架 TX-LCN 执行原理,错误之处望各位不吝指正。 1. 什么情况下需要使用分布式事务? 使用场景很多,先举一个常见:在微服务系统...
  • 这篇文章将给大家介绍一下对分布式事务的一些见解,并讲解分布式事务处理框架 TX-LCN 执行原理,错误之处望各位不吝指正。 1. 什么情况下需要使用分布式事务? 使用场景很多,先举一个常见:在微服务系统...
  • 前言这篇文章将给大家介绍一下对分布式事务的一些见解,并讲解分布式事务处理框架 TX-LCN 执行原理,错误之处望各位不吝指正。1. 什么情况下需要使用分布式事务?使用场景很多,先举一个常见:在微服务系统...
  • 分布式事务五_基于可靠消息最终一致性_异常流程 分布式事务六_常规MQ队列 分布式事务七_幂等性设计 分布式事务八_可靠消息最终一致性方案 分布式事务九_基于可靠消息最终一致性代码 分布式事务10_最大...

空空如也

空空如也

1 2
收藏数 22
精华内容 8
关键字:

lcn分布式事务中的事务是什么