zoukankan      html  css  js  c++  java
  • 从本地事务到分布式事务到微服务下事务

    从本地事务到分布式事务到微服务下事务

     

    一、传统本地事务

        传统单服务器,单关系型数据库下事务比较简单,完全可用很简单的实现ACID,实际中我们实现一个业务时只需要:开启一个事务-操作数据库-提交/回滚这个事务,这样就完美的实现了一次事务操作,更简单点我们通常会通过spring集成事务直接指定在哪些服务什么样的方法执行什么样的事务即可,更甚至我们业务实现基本都忽略了事务,具体图如下:

    二、传统分布式事务

        在传统一服务,一个关系数据库架构基础上,随着访问量的增大,单机很明显已满足不了现状,于是我们顺其自然的就考虑到了服务集群部署,数据库分库分表,从而也就实现了这样一个样子,如图:

    解释:服务水平扩展,数据库分库分表压力是将下来了,但同时也来了另一个问题,如果我一次请求中同时操作了多个DB这个时候我们的传统事务模式(一)就已经不行了,于是我们就在网上各种搜,终于找到了一个叫2PC(二阶段提交)的东西,具体操作如图:

    大概意思:

    在最外层有一个事务管理器(TM)来控制整个事务,一个请求过来,

    第一阶段:事务管理器通知各个资源管理器(RM)准备提交事务,这时我们处理完业务各个RM准备完毕后给TM一个响应(业务正常/异常)

    第二阶段:1、如果反馈TM业务正常那么TM会通知RM可提交事务,如果异常,通知回滚事务

    大概就是这个意思,具体可百度


    三、微服务下事务

         分布式系统,随着业务的不断增加,系统更新、上线频繁,出错率高,于是我们就想到了按照不同的业务线将系统、DB进行拆分形成单独部署的小颗粒系统,系统之间只能通过api的形式调用,而不同于之前的直接操作库表,如图:

    于是就带来了以下问题:

    本系统只能控制本DB事务,通过api调用的无法控制,从而导致了数据不一致的情况

    于是我们最简单的想法就是,我将本地业务和调用远程服务放到一个系统,如果远程服务报错我就回滚,如图:

    很快我们又发现了问题:

    1、如果调用外部服务时耗时较长,那么我们无形中就创建了一个大事务

    2、如果因为接口超时远程服务执行成功,那么我们本地回滚,导致数据不一致

    最终解决方案:

    1、利用消息达到最终一致性

    2、TCC

    下次写消息确保事务的最终一致性

     

     

    Java中的事务——全局事务与本地事务

    上一篇文章中说到过,Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。这是从事务的实现角度区分的,本文从另外一个角度来再次区分一下Java中的事务。

    站在事务管理的角度,可以把Java中用到的事务分为本地事务和全局事务。

    本地事务

    不用事务的编程框架来管理事务,直接使用资源管理器来控制事务。典型的就是java.sql.Connection 中的 setAutoCommitcommitrollback方法。

    本地事务的优点

    • 支持严格的ACID属性
    • 可靠
    • 高效
    • 状态可以只在资源管理器中维护
    • 应用编程模型简单

    本地事务的局限

    • 不具备分布式事务处理能力
    • 隔离的最小单位由资源管理器决定,如数据库中的一条记录

    本地事务比较简单,对事务不太了解的同学可以阅读我的博客中其他关于事务的内容

    全局事务

    前面我们介绍了本地事务,本地事务是我们在编程中比较常接触的事务,比如典型的jdbc操作,在保证ACID方面做的非常出色。但是本地事务无法解决分布式场景中的事务问题。

    前面的文章中专门介绍过分布式场景中为什么需要事务。这里我再稍微回顾一下。

    典型的分布式事务场景

    • 转账

      • 对于银行账户间转账的问题。账户A向账户B转账,从实现上来看,一般可以拆分为“从账户A中扣钱”、“向账户B中加钱”两个操作步骤,两个账户大多数情况下会被切分到不同的数据库上,更多的是,两个操作会是两次服务调用。这两个操作要求做到要么同时成功、要么同时失败。因此引入了分布式事务问题。
    • 下单

      • 在电商网站上,在消费者点击购买按钮后,交易后台会进行库存检查、下单、减库存、更新订单状态等一连串的服务调用,每一个操作对应一个独立的服务,服务一般会有独立的数据库,因此会产生分布式事务问题。

    由于用一次操作,数据要写入的数据库不一致,或者调用的服务都是RPC服务,那么就会无法保证操作在同一个事务中被处理掉。所以就会存在分布式的事务问题。


    全局事务的定义

    在上面的场景中会出现分布式事务问题,那么全局事务就是一个标准的分布式事务。下面我们尝试着给全局事务下一个定义:

    全局事务是由资源管理器管理和协调的事务。

    全局事务是一个DTP模型的事务,所谓DTP模型指的是X/Open DTP(X/Open Distributed Transaction Processing Reference Model),是X/Open 这个组织定义的一套分布式事务的标准,也就是了定义了规范和API接口,由这个厂商进行具体的实现。

    X/Open DTP 定义了三个组件:APTMRM 和两个协议:XATX

    AP(Application Program):也就是应用程序,可以理解为使用DTP的程序

    RM(Resource Manager):资源管理器,这里可以理解为一个DBMS系统,或者消息服务器管理系统,应用程序通过资源管理器对资源进行控制。

    TM(Transaction Manager):事务管理器,负责协调和管理事务,提供给AP应用程序编程接口以及管理资源管理器。

    XA协议:应用或应用服务器与事务管理之前通信的接口

    TX协议:全局事务管理器与资源管理器之间通信的接口

    事务管理器控制着全局事务,管理事务生命周期,并协调资源。资源管理器负责控制和管理实际资源。

    这里还要提到一个点,就是2PC(两阶段提交),在全局事务中,为了保证所有的操作可以一次性要么全提交,要么全失败。事务管理器和资源管理器之间的事务操作的控制是采用2PC来进行的,关于2PC,我博客中有文章专门介绍,这里不再赘述。

    J2EE中全局事务的实现

    Java自身提供了一些API可以用来实现全局事务。Java中的事务——JDBC事务和JTA事务中介绍的JTA事务就可以用来实现J2EE中的全局事务。

    JTA(Java Transaction API):面向应用、应用服务器与资 源管理器的高层事务接口。

    JTS(Java Transaction Service):JTA事务管理器的实现标 准,向上支持JTA,向下通过CORBA OTS实现跨事务域的互 操作性。

    EJB:基于组件的应用编程模型,通过声明式事务管理进一步 简化事务应用的编程。

    全局事务的优缺点

    全局事务,作为一种标准的分布式事务解决方案,他解决了本地事务无法满足分布式场景中数据的ACID的要求。

    关于分布式事务、两阶段提交协议、三阶提交协议中我曾经介绍过,2PC本身是存在同步阻塞问题,这就会导致效率变低,所以,采用2PC进行事务控制的全局事务也必然存在效率低的问题。这也是全局事务最致命的缺点,在提倡微服务的今天,这是不能容忍的。

    总结

    本文主要介绍了本地事务和全局事务,本地事务很简单,在Java中可以使用JDBC来实现本地事务,全局事务是一种基本的分布式事务解决方案,是符合DTP模型的事务管理机制。

    目前,越来越多的web开发要涉及到分布式事务,尤其是微服务架构最近越来越火,在微服务架构中,分布式事务是必然存在的。对于分布式事务的处理,本文主要介绍了一个典型的方案——全局事务。但是实际上,低效率的全局事务并不是很适合用来解决大型网站的分布式事务问题。

    在业内,主要用来解决分布式事务的方案是使用柔性事务。柔性事务包括几种类型:两阶段型、补偿型、异步确保型和最大努力通知型。后面我会有文章继续介绍柔性事务。请继续关注。

     
     

    分布式事务解决方案框架(LCN)

     

    事物概念

    事物特性(ACID)

    原子性(A)

    所谓的原子性就是说,在整个事务中的所有操作,要么全部完成,要么全部不做,没有中间状态。对于事务在执行中发生错误,所有的操作都会被回滚,整个事务就像从没被执行过一样。

    一致性(C)

    事务的执行必须保证系统的一致性,就拿转账为例,A有500元,B有300元,如果在一个事务里A成功转给B50元,那么不管并发多少,不管发生什么,只要事务执行成功了,那么最后A账户一定是450元,B账户一定是350元。

    隔离性(I)

    所谓的隔离性就是说,事务与事务之间不会互相影响,一个事务的中间状态不会被其他事务感知。

    持久性(D)

    所谓的持久性,就是说一单事务完成了,那么事务对数据所做的变更就完全保存在了数据库中,即使发生停电,系统宕机也是如此。

    这种特性 简称 刚性事物

    分布式事物

    分布式事物产生原因

     
    分布式事物产生的原因
     
    分布式事务产生的场景

    在分布式系统,都会垂直拆分数据库,分为支付数据库、订单数据库、积分数据库、优惠全数据库等,业务组成,分为多个数据源,会产生分布式事物问题。

    spring事务和分布式事务的区别是什么?
    spring事务,本地事务
    分布式事务是跨服务间的通讯(不同的数据库连接)

    分布式理论知识

    CPA理论

     

    CAP由Eric Brewer在2000年PODC会议上提出[1][2],是Eric Brewer在Inktomi[3]期间研发搜索引擎、分布式web缓存时得出的关于数据一致性(consistency)、服务可用性(availability)、分区容错性(partition-tolerance)的猜想:

    • 数据一致性(consistency):如果系统对一个写操作返回成功,那么之后的读请求都必须读到这个新数据;如果返回失败,那么所有读操作都不能读到这个数据,对调用者而言数据具有强一致性(strong consistency) (又叫原子性 atomic、线性一致性 linearizable consistency)[5]

    • 服务可用性(availability):所有读写请求在一定时间内得到响应,可终止、不会一直等待

    • 分区容错性(partition-tolerance):在网络分区的情况下,被分隔的节点仍能正常对外服务

    Base理论

    BASE理论是指,Basically Available(基本可用)、Soft-state( 软状态/柔性事务)、Eventual Consistency(最终一致性)。是基于CAP定理演化而来,是对CAP中一致性和可用性权衡的结果。核心思想:即使无法做到强一致性,但每个业务根据自身的特点,采用适当的方式来使系统达到最终一致性。

    1、基本可用:指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用。但不等价于不可用。比如:搜索引擎0.5秒返回查询结果,但由于故障,2秒响应查询结果;网页访问过大时,部分用户提供降级服务,等。

    2、软状态:软状态是指允许系统存在中间状态,并且该中间状态不会影响系统整体可用性。即允许系统在不同节点间副本同步的时候存在延时。

    3、最终一致性:

    系统中的所有数据副本经过一定时间后,最终能够达到一致的状态,不需要实时保证系统数据的强一致性。最终一致性是弱一致性的一种特殊情况。BASE理论面向的是大型高可用可扩展的分布式系统,通过牺牲强一致性来获得可用性。ACID是传统数据库常用的概念设计,追求强一致性模型。

    ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

    柔性事务和刚性事务

    柔性事务满足BASE理论(基本可用,最终一致)

    刚性事务满足ACID理论

    本文主要围绕分布式事务当中的柔性事务的处理方式进行讨论。

    柔性事务分为

    1. 两阶段型

    2. 补偿型

    3. 异步确保型

    4. 最大努力通知型几种。 由于支付宝整个架构是SOA架构,因此传统单机环境下数据库的ACID事务满足了分布式环境下的业务需要,以上几种事务类似就是针对分布式环境下业务需要设定的。

    什么是XA接口

    XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理如下:

     

    什么是Jta

    作为java平台上事务规范JTA(Java Transaction API)也定义了对XA事务的支持,实际上,JTA是基于XA架构上建模的,在JTA 中,事务管理器抽象为javax.transaction.TransactionManager接口,并通过底层事务服务(即JTS)实现。像很多其他的java规范一样,JTA仅仅定义了接口,具体的实现则是由供应商(如J2EE厂商)负责提供,目前JTA的实现主要由以下几种:

    1.J2EE容器所提供的JTA实现(JBoss)
    2.独立的JTA实现:如JOTM,Atomikos.这些实现可以应用在那些不使用J2EE应用服务器的环境里用以提供分布事事务保证。如Tomcat,Jetty以及普通的java应用。

    基于XA协议的两阶段(2PC)提交

    所谓的两个阶段是指:第一阶段:准备阶段(投票阶段)和第二阶段:提交阶段(执行阶段)。

    XA一般由两阶段完成,称为two-phase commit(2PC)。

    阶段一为准备阶段,即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager汇报自己已经准备好。

    阶段二为提交阶段。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。

    如下图所示:

     

    XA的性能问题

    XA的性能很低。一个数据库的事务和多个数据库间的XA事务性能对比可发现,性能差10倍左右。因此要尽量避免XA事务,例如可以将数据写入本地,用高性能的消息系统分发数据。或使用数据库复制等技术。

    只有在这些都无法实现,且性能不是瓶颈时才应该使用XA。

    分布式事物解决方案

    分布式事物问题,在互联网公司比较常见,例如“”分布式事物解决方案 可以使用全局事物2pc(两段提交协议)、3pc(三段提交协议),消息中间件、tcc、gts、提供回滚接口、分布式数据库

    2PC和3PC区别:https://blog.csdn.net/secretx/article/details/53322989
    LCN 核心采用3PC+TCC补偿机制

    使用LCN框架解决分布式事务

    什么是LCN框架

    LCN分布式事务框架v4.0 https://www.txlcn.org
    "LCN并不生产事务,LCN只是本地事务的搬运工"

    框架特点

    兼容SpringCloud、Dubbo

    使用简单,低依赖,代码完全开源

    基于切面的强一致性事务框架

    高可用,模块可以依赖Dubbo或SpringCloud的集群方式做集群化,TxManager也可以做集群化

    支持本地事务和分布式事务共存

    事务补偿机制,服务故障或挂机再启动时可恢复事务

    LCN框架原理

    参考网站 https://github.com/codingapi/tx-lcn/wiki/LCN%E5%8E%9F%E7%90%86

     
    lcn框架原理

    核心步骤

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

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

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

  • 相关阅读:
    VA对于开发QT是神器,VA自动补全QT
    64位下好神奇啊(增加了PatchGuard技术保护自己,SSDT是相对地址,参数通过寄存器与rdi来传递)
    贵在坚持
    VC程序查错之内存访问异常
    QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数
    QTimer源码分析(以Windows下实现为例)
    Go语言的优点(oschina讨论)
    致诸位新程序员:来自Chuck Jazdzewski慈父般的忠告
    poj1483 It's not a Bug, It's a Feature!
    App应用与思考
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/11898640.html
Copyright © 2011-2022 走看看