精华内容
下载资源
问答
  • 2PC即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase),2是指两阶段,P是指准备阶段,C是提交阶段。 举例 :张三和李四好久不见,两人一起约看电影,电影院...

    针对不同的分布式场景业界常见的解决方案有2PCTCC可靠消息最终一致性最大努力通知等。

    1. 什么是2PC

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

    举例 :张三和李四好久不见,两人一起约看电影,电影院收银员要求先买单,才能出电影票。这时张三和李四分别抱怨近况不如意,囊肿羞涩,都不愿意请客,这时只能AA。只有张三和李四都付款,老板才能出票安排电影。但由于张三和李四都是铁公鸡,形成两尴尬的一幕 :
    准备阶段 :收银员分别要求张三、李四付款付款,张三付款、李四付款。
    提交阶段 :收银员出票,两人拿票纷纷进入电影院。
    例子中形成两一个事务,若张三或李四其中一个拒绝付款,或钱不够,店老板都不会给出票,并且会把已收款退回。
    整个事务过程由事务管理器和参与者组成,店老板就是事务管理器,张三、李四就是事务参与者,事务管理器负责决策整个分布式事务的提交和回滚,事务参与者负责自己本地事务的提交和回滚。
    在计算机中部分关系数据库如Oracle、MySQL支持两阶段提交协议,如下图 :

    1. 准备阶段(Prepare phase):事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。
      (Undo日志是记录修改前的数据,用于数据库回滚,Redo日志是记录修改后的数据,用于提交事务后写入数据文件)
    2. 提交阶段(commit phase):如果事务管理器收到两参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意 :必须在最后阶段释放锁资源。

    下图展示两2PC的两个阶段,分成功和失败两个情况说明 :
    成功情况:
    在这里插入图片描述
    失败情况 :
    在这里插入图片描述

    2. 2PC解决方案

    2.1 XA方案

    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模型定义如下角色 :

    • AP(Application Program) : 应用程序,可以理解为使用DTP分布式事务的程序。
    • RM(Resource Manager) : 资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务。
    • TM(Transaction Manager) : 事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。
    • DTP模型定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接口协议,基于数据库的XA协议来实现2PC又称为XA方案。

    以上三个角色之间的交互方式如下 :
    1)TM向AP提供应用程序编程接口,AP通过TM提交及回滚事务。
    2)TM交易中间件通过XA接口来通知RM数据库事务的开始、结束以及提交、回滚等。

    2.1.1 XA方案总结

    整个2PC的事务流程涉及到三个角色AP、RM、TM。AP指的是使用2PC分布式事务的应用程序;RM指的是资源管理器,它控制着分支事务;TM指的是事务管理器,它控制着整个全局事务。

    1. 在准备阶段RM执行实际的业务操作,但不提交事务,资源锁定;
    2. 在提交阶段TM会接收RM在准备阶段的执行回复,只要有任一个RM执行失败,TM会通知所有RM执行回滚操作,否则,TM将会通知所有RM提交该事务。提交阶段结束资源锁释放。
    2.1.2 XA方案的问题 :
    1. 需要本地数据库支持XA协议。
    2. 资源锁需要等到两个阶段结束才释放,性能较差。

    2.2 Seata方案

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

    Seata的设计思想如下 :
    Seata的设计目标其一是对业务无入侵,因此从业务无入侵的2PC方案着手,在传统2PC的基础上演进,并解决2PC方案面临的问题。
    Seata把一个分布式事务理解成一个包含来若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚。此外,通常分支事务本身就是一个关系数据库的本地事务,下图是全局事务与分支事务的关系图 :


    与传统2PC的模型类似,Seata定义了三个组件来协议分布式事务的处理过程 :
    在这里插入图片描述

    • Transaction Coordinator(TC)事务协调器,它是独立的中间件,需要独立部署运行,它维护全局事务的运行状态,接收- TM指令发起全局事务的提交与回滚,负责与RM通信协调各个分支事务的提交或回滚。
    • Transaction Manager(TM)事务管理器,TM需要嵌入应用程序中工作,它负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的指令。
    • Resource Manager(RM)控制分支事务,负责分支注册、状态汇报,并接收事务协调器TC的指令,驱动分支(本地)事务的提交和回滚。

    参考官网中用户购买商品的业务逻辑。整个业务逻辑由4个微服务提供支持:

    • 库存服务:扣除给定商品的存储数量。
    • 订单服务:根据购买请求创建订单。
    • 帐户服务:借记用户帐户的余额。
    • 业务服务:处理业务逻辑。

    请求逻辑架构
    在这里插入图片描述
    分布式事务控制的整个流程如下下图:
    在这里插入图片描述
    具体的执行流程如下 :

    1. 业务服务的TMTC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
    2. 账户服务、订单服务、库存服务分别的RM向TC注册分支事务,该分支事务在用户服务执行新增用户逻辑,并将其纳入XID对应全局事务的管辖。
    3. 库存服务执行分支事务,向库存表更新一条库存记录(减少商品的库存),执行完毕返回给业务服务。
    4. 订单服务执行分支事务,向订单表插入一条订单记录,同时执行到远程调用账户服务时(XID在微服务调用链路的上下文中传播)。账户服务的RM向TC注册分支事务,该分支事务执行减少账户余额的的逻辑,并将其纳入XID对应全局事务的管辖。
      账户服务执行分支事务,向账户表更新一条记录(减少账户余额),执行完毕后,返回订单服务。
    5. 订单服务分支事务执行完毕。
    6. TM向TC发起针对XID的全局提交或回滚决议。
    7. TC调度XID下管辖的全部分支事务完成提交或回滚请求。

    Seata实现2PC与传统2PC的比较 :

    1. 架构层次方面,传统2PC方案的RM实际上是在数据库层,RM本质上就是数据库自身,通过XA协议实现,而Seata的RM是以jar包的形式作为中间件层部署在应用程序的这一侧的。
    2. 两阶段提交方面,传统2PC无论第二阶段的决议是commit还是rollbcak事务性资源的锁都要保持到Phase2完成才释放。而Seata的做法是在Phase1就将本地事务提交,这样就可以省去Phase2持锁的时间,整体提高效率
    展开全文
  • 分布式事务

    千次阅读 2021-04-07 21:39:07
    分布式事务

    分布式事务

    前言:

    什么是事务

    举个生活中的例子:

    • 你去小卖铺买东西,“一手交钱,一手交货”就是一个事务的例子
    • 交钱和交货 必须全部成功,事务才算成功任一个活动失败,事务将撤销所有已成功的活动。
    • 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。

    数据库事务的四大特性 ACID:

    A(Atomic):原子性

    • 构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。

    C(Consistency):一致性

    • 在事务执行前后,数据库的一致性约束没有被破坏。
    • 比如
      张三100元 ,李四100元,一共200。
      李四给张三50
      李四50元, 张三150元,一共还是200元!

    I(Isolation):隔离性

    • 数据库中的事务一般都是并发的,
    • 隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务运行过程的中间状态。
    • 通过配置事务隔离级别可以避脏读、重复读等问题

    D(Durability):持久性

    • 事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚

    本地事务 Local Transaction

    • 起初,事务仅限于对单一数据库资源的访问控制 架构服务化以后,事务的概念延伸到了服务中。
    • 倘若将一个单一的服务操作作为一个事务,那么整个服务操作只能涉及一个单一的数据库资源。
    • 这类基于单个服务单一数据库资源访问的事务,被称为本地事务

    分布式事务 | 产生的场景

    • 随着互联网的快速发展,软件系统由原来的 单体应用 转变 为分布式应用
    • 分布式系统会把一个应用系统拆分为可独立部署的多个服务,不同的服务还会有不同的库
      因此需要服务与服务之间远程协作才能完成事务操作
    • 这种分布式系统环境下由不同的服务之间通过网络远程协作,在不同的数据库之间,完成事务称之为分布式事务

    单一服务分布式事务

    • 最早的分布式事务应用架构很简单
    • 不涉及服务间的访问调用,仅仅是服务内操作涉及到对多个数据库资源的访问。
      在这里插入图片描述

    多服务分布式事务

    • 一个服务操作访问不同的数据库资源
      对于上面介绍的分布式事务应用架构,尽管一个服务操作会访问多个数据库资源,但是毕竟整个事务还是控制在单一服务的内部。
    • 一个服务操作需要调用另外一个服务,这时的事务就需要跨越多个服务了
      在这里插入图片描述

    多服务多数据源分布式事务

    • 在多个服务之间,且不同服务存在不同的数据库,的环境下的分布式事务 好牛啊!
      在这里插入图片描述

    事务的作用:

    保证每个事务的数据一致性。

    分布式事务基础理论

    CAP理论

    理解CAP

    • CAP是 Consistency、Availability、Partition tolerance三个词语的缩写分别表示:一致性可用性分区容忍性

    C (一致性)

    • 一致性是指: 写操作后的 读操作可以读取到最新的数据状态 实时更新!
    • 对于数据分布在不同节点上的数据来说
      如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为 强一致
      如果有某个节点没有读取到,那就是 分布式不一致

    A (可用性)

    • 可用性,就是提高程序的高可用… 提高安全…
      类似于搭建 集群,一个服务挂了,其它服务继续工作不影响使用!但这必然影响了C一致性的性能速度!

    • 但注意,可用行 会导致 一致性的效率,但也要保证 最终一致性 这是事务必须的!
      非故障的节点在合理的时间内返回合理的响应  (不是错误和超时的响应)

    • 所以分布式系统理论上不可能选择 CA 架构, 只能选择 CP 或者 AP 架构。

    P (分区容错性)

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

    • 如何实现分区容忍性?
       尽量使用异步取代同步操作
       例如使用异步方式将数据从主数据库同步到从数据,这样结点之间能有效的实现
      松耦合。
       添加从数据库结点,其中一个从结点挂掉其它从结点提供服务。

    • 分布式分区容忍性的特点:
      分区容忍性分是布式系统具备的基本能力。

    CAP有哪些组合方式呢?

    AP:

    • 放弃一致性,追求分区容忍性和可用性。
    • 例如:
      商品管理,完全可以实现AP,前提是只要用户可以接受所查询的到数据在一定时间内不是最新的即可。
      一些业务场景比如: 订单退款,今日退款成功,明日账户到账,只要用户可以接受在一定时间内到账即可。

    CP:

    • 放弃可用性,追求一致性和分区容错性,我们的zookeeper其实就是追求的强一致
    • 一些业务场景比如: 抢购商品 秒杀!

    CA:

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

    面试题:ZooKeeper 和 eureka 的区别

    • ZooKeeper 是 cp eureka 是ap 的架构….

    总结

    • CAP理论告诉我们一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容忍
      性(Partition tolerance)这三项中的两项.

    • 在实际生产中很多场景都要实现一致性
      比如我们举的例子:主数据库向从数据库同步数据,即使不要一致性,但是最终也要将数据同步成功来保证数据一致

    • 其中AP在实际应用中较多,AP即舍弃一致性,保证可用性和分区容忍性

    BASE理论

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

    基本可用:

    • 分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
    • 如,电商网站交易付款出现问题了,商品依然可以正常浏览。

    软状态:

    • 由于不要求强一致性,所以BASE允许系统中存在中间状态(也叫软状态)
    • 这个状态不影响系统可用性,如订单的"支付中"、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。

    最终一致:

    • 最终一致是指经过一段时间后,所有节点数据都将会达到一致。
      如订单的"支付中"状态,最终会变为“支付成功”或者"支付失败",
      使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。

    分布式事务解决方案

    XA分布式事务协议

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

    DTP模型

    在这里插入图片描述
    DTP模型定义如下角色:

    • AP(Application Program):即应用程序,可以理解为使用DTP分布式事务的程序。

    • RM(Resource Manager):即资源管理器
      可以理解为事务的参与者,一般情况下是指一个数据库实例,
      通过资源管理器对该数据库进行控制,资源管理器控制着分支事务。

    • TM(Transaction Manager):事务管理器
      负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个RM。
      全局事务 是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。

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

    两阶段提交协议 Two Phase Commitment Protocol 涉及到两种角色

    • 一个事务协调者(coordinator) TM事务管理器
      负责协调多个参与者进行事务投票及提交(回滚)
    • 多个事务参与者(participants) RM资源管理器
      即本地事务执行者

    总共处理步骤有两个

    • 投票阶段(voting phase) 参与者操作
      协调者将通知,事务参与者 准备提交或取消事务,然后进入表决过程投票阶段参与者将告知协调者自己的决策
      true: 事务参与者,本地事务执行成功,但未提交
      flase: 本地事务执行故障

    • 提交阶段(commit phase) 协调者操作
      收到参与者的通知后,协调者再向参与者发出通知,根据反馈投票情况决定,各参与者是否要提交还是回滚
      多个参与者,只要有一个false , 就表示事务执行失败,通知所有的参与者未提交的事务进行回滚!

      在这里插入图片描述

    2PC总结:

    • 整个2PC的事务流程涉及到三个角色AP、RM、TM。
    • AP指的是使用2PC分布式事务的应用程序;
    • RM指的是资源管理器,它控制着分支事务;
    • TM指的是事务管理器,它控制着整个全局事务。

    缺点:

    • 投票阶段,RM执行实际的业务操作,但不提交事务,资源锁定

    • 协调者单点故障问题 3PC阶段解此问题!
      事务协调者是整个XA模型的核心,
      一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知。参与者会一直处于中间状态无法完成事务。

    • 丢失消息导致的不一致问题。
      在XA协议的第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息
      另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致…!!


    Seata 实现2PC

    Seata方案

    • Seata是由阿里中间件团队发起的开源项目 Fescar,
      后更名为Seata Simple Extensible Autonomous Transaction Architecture 一套一站式分布式事务解决方案。

    解决分布式事务问题,有两个设计初衷

    • 对业务无侵入
      即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入,实际开发中只要一个注解就搞定了!@Configuration
    • 高性能
      减少分布式事务解决方案所带来的性能消耗,添加 undo_log 表,本地放心提交事务,可以依靠undo_log进行回滚处理..

    seata中有两种分布式事务实现方案:ATTCC

    • 本人目前只会AT的…😢 Seata AT模式是基于 XA事务演进而来的一个分布式事务中间件

    Seata的设计思想:

    Seata的设计目标其一是对业务无侵入,因此从业务无侵入的2PC方案着手 在传统2PC的基础上演进,并解决 2PC方案面临的问题, 第二阶段资源占用!

    与 传统2PC 的模型类似,Seata定义了3个组件来协议分布式事务的处理过程:

    在这里插入图片描述

    • Transaction Manager (TM ): 事务管理器
      控制全局事务的边界,负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的决议。

    • Transaction Coordinator (TC): 事务协调器
      事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。

    • Resource Manager (RM): 控制分支事务
      控制分支事务,负责分支注册、状态汇报(投票),
      并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

    具体执行流程:

    第一阶段
    在这里插入图片描述

    • 在一阶段,Seata 会拦截“业务 SQL”
    • 首先解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”快照 存在undo_log表中!
    • 然后执行“业务 SQL”更新业务数据,在业务数据更新之后,再将其保存成“after image”,最后生成行锁。
      数据库行锁:确保多线程情况下,改记录只能由一个线程操作!
    • 以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
    • TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID 确保后面执行...

    第二阶段
    提交
    在这里插入图片描述

    • 第二阶段如果是提交的话,因为业务SQL在一阶段已经提交至数据库(已通过)
    • 所以 Seata 框架只需将一阶段保存的快照数据和行锁删掉,完成数据清理即可。 极大提高了第二阶段的执行性能!

    回滚
    在这里插入图片描述

    • 第二阶段如果是回滚的话
      Seata就需要回滚一阶段已执行的的业务SQL。当然回滚方式是使用before image镜像还原业务数据。
    • RM 收到协调器发来的回滚请求,通过 XID线程id 和 Branch ID 分支id 找到相应的回滚日志记录
    • 在还原之前还要进行校验脏写
      判断当前的数据,和undo表中,执行后的数据是否一致. 事务执行后的数据是否被更改过!
       
      如果两份数据完全一致就说明没有脏写,可以还原业务数据
      如果不一致就说明有脏写,出现脏写就需要转人工处理。

    Seata 2PC与传统2PC的差别

    架构层次方面

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

    两阶段提交方面

    • 传统2PC无论第二阶段的决议是commit还是rollback 事务性资源的锁都要保持到 第二阶段完成才释放。
    • 而Seata的做法是在 阶段一就将本地事务提交将提交前的数据信息,保存在undo_log表中...,这样就可以省去阶段二持锁的时间,整体提高效率。

    Spring Cloud 快速集成 Seata

    • 上面理论,了解即可…具体的本人还不是很清除后面可能会整理学习…目前会用即可!
    • Seata使用起来还是非常简单的!
    • Github 集成文档

    依赖:

    • 一般给要管理的微服加入即可,但因为几乎所有的微服都需要,所有就放在公共的util微服里了!
    	<dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-alibaba-seata</artifactId>
             <version>2.1.0.RELEASE</version>
         </dependency>
    

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    因为:
    spring-cloud-starter-alibaba-seata 这个依赖中只依赖了spring-cloud-alibaba-seata
    所以在项目中添加spring-cloud-starter-alibaba-seataspring-cloud-alibaba-seata是一样的

    添加配置文件

    • 同上一般都放在公共的 util微服模块的, resourece资源文件目录下:

    registry.conf

    • 该配置用于指定 TC 的注册中心和配置文件,默认都是 file;
    • 如果使用其他的注册中心,要求 Seata-Server 也注册到该配置中心上
    registry {
      # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
      type = "file"			#默认 file文件类型
    
      nacos {
        serverAddr = "localhost"
        namespace = "public"
        cluster = "default"
      }
      eureka {
        serviceUrl = "http://localhost:8761/eureka"
        application = "default"
        weight = "1"
      }
      redis {
        serverAddr = "localhost:6379"
        db = "0"
      }
      zk {
        cluster = "default"
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      consul {
        cluster = "default"
        serverAddr = "127.0.0.1:8500"
      }
      etcd3 {
        cluster = "default"
        serverAddr = "http://localhost:2379"
      }
      sofa {
        serverAddr = "127.0.0.1:9603"
        application = "default"
        region = "DEFAULT_ZONE"
        datacenter = "DefaultDataCenter"
        cluster = "default"
        group = "SEATA_GROUP"
        addressWaitTime = "3000"
      }
      file {
        name = "file.conf"
      }
    }
    
    config {
      # file、nacos 、apollo、zk、consul、etcd3
      type = "file"
    
      nacos {
        serverAddr = "localhost"
        namespace = "public"
        cluster = "default"
      }
      consul {
        serverAddr = "127.0.0.1:8500"
      }
      apollo {
        app.id = "seata-server"
        apollo.meta = "http://192.168.1.204:8801"
      }
      zk {
        serverAddr = "127.0.0.1:2181"
        session.timeout = 6000
        connect.timeout = 2000
      }
      etcd3 {
        serverAddr = "http://localhost:2379"
      }
      file {
        name = "file.conf"
      }
    }
    

    file.conf

    • 该配置用于指定TC的相关属性;如果使用注册中心也可以将配置添加到配置中心
    transport {
      # tcp udt unix-domain-socket
      type = "TCP"
      #NIO NATIVE
      server = "NIO"
      #enable heartbeat
      heartbeat = true
      #thread factory for netty
      thread-factory {
        boss-thread-prefix = "NettyBoss"
        worker-thread-prefix = "NettyServerNIOWorker"
        server-executor-thread-prefix = "NettyServerBizHandler"
        share-boss-worker = false
        client-selector-thread-prefix = "NettyClientSelector"
        client-selector-thread-size = 1
        client-worker-thread-prefix = "NettyClientWorkerThread"
        # netty boss thread size,will not be used for UDT
        boss-thread-size = 1
        #auto default pin or 8
        worker-thread-size = 8
      }
      shutdown {
        # when destroy server, wait seconds
        wait = 3
      }
      serialization = "seata"
      compressor = "none"
    }
    service {
      #vgroup->rgroup
      vgroup_mapping.my_test_tx_group = "default"
      #only support single node
      default.grouplist = "127.0.0.1:8091"
      #degrade current not support
      enableDegrade = false
      #disable
      disable = false
      #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
      max.commit.retry.timeout = "-1"
      max.rollback.retry.timeout = "-1"
    }
    
    client {
      async.commit.buffer.limit = 10000
      lock {
        retry.internal = 10
        retry.times = 30
      }
      report.retry.count = 5
    }
    
    ## transaction log store
    store {
      ## store mode: file、db
      mode = "file"
    
      ## file store
      file {
        dir = "sessionStore"
    
        # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
        max-branch-session-size = 16384
        # globe session size , if exceeded throws exceptions
        max-global-session-size = 512
        # file buffer size , if exceeded allocate new buffer
        file-write-buffer-cache-size = 16384
        # when recover batch read size
        session.reload.read_size = 100
        # async, sync
        flush-disk-mode = async
      }
    
      ## database store
      db {
        ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
        datasource = "dbcp"
        ## mysql/oracle/h2/oceanbase etc.
        db-type = "mysql"
        url = "jdbc:mysql://127.0.0.1:3306/seata"
        user = "mysql"
        password = "mysql"
        min-conn = 1
        max-conn = 3
        global.table = "global_table"
        branch.table = "branch_table"
        lock-table = "lock_table"
        query-limit = 100
      }
    }
    lock {
      ## the lock store mode: local、remote
      mode = "remote"
    
      local {
        ## store locks in user's database
      }
    
      remote {
        ## store locks in the seata's server
      }
    }
    recovery {
      committing-retry-delay = 30
      asyn-committing-retry-delay = 30
      rollbacking-retry-delay = 30
      timeout-retry-delay = 30
    }
    
    transaction {
      undo.data.validation = true
      undo.log.serialization = "jackson"
    }
    
    ## metrics settings
    metrics {
      enabled = false
      registry-type = "compact"
      # multi exporters use comma divided
      exporter-list = "prometheus"
      exporter-prometheus-port = 9898
    }
    

    修改应用程序yml

    • 在各个需要分布式事务的模块添加yml,并且指定file.conf中配置通信指定组名my_test_tx_group

    .yml

    spring:
      cloud:
        alibaba:
          seata:
            tx-service-group: my_test_tx_group
    

    注入数据源

    • 同上,为了方便操作 一般直接放在公共的util 模块中
    • Seata 通过代理数据源的方式实现分支事务,MyBatis和JPA都需要注入 io.seata.rm.datasource.DataSourceProxy
    • 不同的是MyBatis 还需要额外注入 org.apache.ibatis.session.SqlSessionFactory

    DataSourceProxyConfig.Java

    import com.alibaba.druid.pool.DruidDataSource;
    import io.seata.rm.datasource.DataSourceProxy;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import javax.sql.DataSource;
    
    @Configuration
    public class DataSourceProxyConfig {
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource dataSource() {
            return new DruidDataSource();
        }
    
        @Bean
        public DataSourceProxy dataSourceProxy(DataSource dataSource) {
            return new DataSourceProxy(dataSource);
        }
    	//JPA 不需要注入sqlSessionFactoryBean
        @Bean
        public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dataSourceProxy);
            return sqlSessionFactoryBean.getObject();
        }
    }
    

    添加 undo_log 表

    • 在业务相关的数据库中添加 undo_log 表,用于保存需要回滚的数据 每个参与分布式事务都要加这个库!
    • 分布式事务是多个数据库的操作,给每个数据库加入一个 undo_log日志表!

    undo_log.sql

    CREATE TABLE `undo_log`
    (
        `id`            BIGINT(20)   NOT NULL AUTO_INCREMENT,
        `branch_id`     BIGINT(20)   NOT NULL,
        `xid`           VARCHAR(100) NOT NULL,
        `context`       VARCHAR(128) NOT NULL,
        `rollback_info` LONGBLOB     NOT NULL,
        `log_status`    INT(11)      NOT NULL,
        `log_created`   DATETIME     NOT NULL,
        `log_modified`  DATETIME     NOT NULL,
        `ext`           VARCHAR(100) DEFAULT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE = InnoDB
      AUTO_INCREMENT = 1
      DEFAULT CHARSET = utf8
    

    在这里插入图片描述

    启动 Seata-Server

    • 需要的朋友,在 https://github.com/seata/seata/releases 下载相应版本的 Seata-Server
    • 修改 registry.conf为相应的配置(如果使用 file 则不需要修改)
    • Seata解压即用,一般不需要配置任何东西!
    • 启动 sh ./bin/seata-server.sh
      在这里插入图片描述

    使用@GlobalTransactional开启事务

    • 在业务的发起方的方法上使用@GlobalTransactional开启全局事务 就是你业务执行的总方法!

    • Seata 会将事务的 xid 通过拦截器添加到调用其他服务的请求中,实现分布式事务

    • 在事务调度的 总方法上加 @GlobalTransactional 全局事务注解


    基于XA协议的三阶段提交(3PC)

    3PC三阶段,提交是在二阶段提交上的改进版本,主要是加入了超时机制。同时在 协调者和参与者中都引入超时机制

    • XA三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制。
    • 一旦事物参与者迟迟没有接到协调者的commit请求,会自动进行本地commit。这样有效解决了协调者单点故障的问题。
    • 但是性能问题和不一致的问题仍然没有根本解决。需要开发者介入!

    三阶段将二阶段 准备阶段拆分为2个阶段

    • 在原先的 准备提交can Commit 后面 插入了一个preCommit 预提交阶段
    • 以此来处理原先:二阶段参与者准备后,协调者发生崩溃或错误 导致参与者无法知晓是否提交或回滚的不确定状态所引起的延时问题。

    阶段一 canCommit

    • 不变一切正常
    • 协调者向参与者发送 commit 请求,参与者如果可以提交就返回 yes 响应(参与者不执行事务操作),否则返回 no 响应;

    阶段二 preCommit

    • 协调者根据阶段 1 canCommit 参与者的反应情况来决定是否可以进行基于事务的 preCommit 操作。
    • 根据响应情况,有以下两种可能

    情况 1:阶段 1 所有参与者均反馈 yes,参与者预执行事务
    在这里插入图片描述

    • 协调者向所有参与者发出 preCommit 请求,进入准备阶段。
    • 参与者收到 preCommit 请求后,执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)。
    • 各参与者向协调者反馈 ack 成功响应或 no 失败响应,并等待最终指令。

    情况 2:阶段 1 任何一个参与者反馈 no,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务
    在这里插入图片描述

    • 协调者向所有参与者发出 abort 请求。
    • 无论收到协调者发出的 abort 请求,或者在等待协调者请求过程中出现超时,参与者均会中断事务。
    • 即:
      阶段一返回一个 no 中断所有事务 参与者 未接收到 协调者消息 中断本身事务! 解决了协调者突然挂了的情况!

    阶段三 do Commit

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

    情况一 阶段 2 所有参与者均反馈 ack 响应,执行真正的事务提交
    在这里插入图片描述

    • 如果协调者处于工作状态,则向所有参与者发出 do Commit 请求。
    • 参与者收到 do Commit 请求后,会正式执行事务提交,并释放整个事务期间占用的资源。
    • 各参与者向协调者反馈 ack 完成的消息。
    • 协调者收到所有参与者反馈的 ack 消息后,即完成事务提交。

    情况二 阶段 2 任何一个参与者反馈 no,或者 等待超时后 协调者尚无法收到所有参与者的反馈,即中断事务
    在这里插入图片描述

    • 如果协调者处于工作状态,向所有参与者发出 abort 请求。
    • 参与者使用阶段 1 中的 undo 信息执行回滚操作,并释放整个事务期间占用的资源。
    • 各参与者向协调者反馈 ack 完成的消息。
    • 协调者收到所有参与者反馈的 ack 消息后,即完成事务中断。

    注意:

    • 进入阶段 3 后,无论协调者出现问题,或者协调者与参与者网络出现问题
      都会导致参与者无法接收到协调者发出的 do Commit 请求或 abort 请求。
    • 此时,参与者都会在等待超时之后,继续执行事务提交。

    优点:

    • 相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。
    • 避免了协调者单点问题,阶段 3 中协调者出现问题时,参与者会继续提交事务。

    缺点:

    • 数据不一致问题依然存在
    • 当在参与者收到 preCommit 请求后等待 do commite 指令时,此时如果协调者请求中断事务
    • 而协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。
    • 即:阶段三如果 协调者出现故障,仍会导致数据事务不一致!!需要开发者介入!

    TCC三段提交

    • TCC是Try尝试、Confirm确认、Cancel撤销三个词语的缩写
      Try操作做业务检查及资源预留
      Confirm做业务确认操作
      Cancel实现一个与Try相反的操作 即回滚操作
    • TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败
    • TM将会发起所有分支事务的Cancel操作,
    • 若try操作全部成功,TM将会发起所有分支事务的Confirm操作
    • 其中Confirm/Cancel操作若执行失败,TM会进行重试。

    在这里插入图片描述

    其实从思想上看和 2PC 差不多,都是先试探性的执行,如果都可以那就真正的执行,如果不行就回滚。
    流程还是很简单的

    • 难点在于业务上的定义,对于每一个操作你都需要定义三个动作分别对应Try - Confirm - Cancel
      因此 TCC 对业务的侵入较大和业务紧耦合 需要根据特定的场景和业务逻辑来设计相应的操作。 很多时候需要手动补偿代码!
    • 注意 撤销和确认操作的执行可能需要重试,因此还需要保证操作的幂等。
       
      幂等: 无论程序执行n次,保证最终执行结果唯一!

    2PC 和 3PC 都是数据库层面的,而 TCC 是业务层面的分布式事务

    • 开发者,手动编写逻辑,进行提交回滚,补偿代码 发送短信等…
    • 目前本人没有具体的了解… 后面也许会更新!

    本地消息表 (MQ+Table) 最终一致性

    • 学习之前需要了解: MQ 定时框架 本人使用的RabbitMQ 这个问题不大!

    可靠消息最终一致性事务

    • 利用消息中间件来异步完成事务的后一半更新,实现系统的最终一致性 这个方式避免了像XA协议那样的性能问题。

    方案简介:

    • 本地消息表的方案最初是由 eBay 提出, 核心思路是将分布式事务拆分成 一个个,本地事务进行处理。
    • 事务发起方 服务 数据库额外新建 事务执行消息表
    • 事务发起方,发起处理业务开启事务并记录消息在 事务消息表中
    • 通过 定时查看,事务消息表的数据发送事务消息
    • 事务被动方基于——消息中间件——消费事务消息表中的事务。 进行处理!

    优点:

    • 可以避免: 业务处理成功 + 事务消息发送失败业务处理失败 + 事务消息发送成功 多个系统事务的数据 最终 一致性

    缺点:

    • 与具体的业务场景绑定,耦合性强,不可公用。
    • 消息数据与业务数据同库,占用业务系统资源。
    • 业务系统在使用关系型数据库的情况下,消息服务性能会受到关系型数据库并发性能的局限。

    业务实现:

    • 上面的说法可能不是很清晰,这里可以结合业务场景进行处理!

    • 某学习平台,用户下单购买商品教程——产生订单———用户: 学习模块添加任务 学习课程! 随便编的业务别杠
      在这里插入图片描述

    • 支付成功后,订单服务向本地数据库更新订单状态,
      并向 消息表 写入“添加选课消息” task_his.sql:任务信息 mq 交换机/队列 version版本...
      这里的 操作是本地事务执行 要么全部失败,要么全部成功!   如果这里,就事务执行失败了,直接回滚 事务失败!

    • 通过 定时框架 定时扫描 task_his.sql 表信息,向MQ中发送消息
      避免了如果在发送消息时候,网络动荡消息发送失败!定时发送...

    • MQ 通过 Confirm 消息确认 100%发送消息
      确保消息一定会发送到MQ 上!
      对于这里,因为定时框架会每隔一段时间,就扫描 消息表 循环向mq 上发消息!
      mq 发送成功就成功! 删除,消息表中的任务...
      mq 发送失败, 也不会立刻,重新发送等待下次定时任务... 当然如果直接重新发送也行 不同场景不同处理!
      反正无论如何都会发的MQ 上!

    • 学习模块实时监听 MQ的消息队列,只要有新消息就接收,并继续执行自己的业务操作 同时获取自己的结果消息 事务成功/失败
      根据MQ的 消息确认接收机制(ACK) 消息一旦被消费者接收返回 ack,队列中的消息就会被删除。
      使用手动ACK: 消息接收后,不会立刻发送ACK , 学习模块事务执行完毕才返回 ack 确保了消息的消费!
      学习模块的事务无论执行成功/失败,都会在像MQ发送一条消息!
       
      注意 这里还是要做 幂等的操作! 无论程序执行n次,对于相同的请求保证结果唯一!
      方式很多,可以是根据任务请求内容,获取订单id 判断是否执行过…

    • 订单模块接收MQ 上消息,判断事务是否执行成功!回滚/提交。
      并删除消息表的消息!
      就避免了消息在次 定时发送!

    MQ: ack 和 Confirm 消息确认

    ack 保证消息一定被消费

    • 消息一旦被消费者接收,队列中的消息就会被删除。

    • RabbitMQ怎么知道消息被接收了呢?
      如果消费者领取消息后,还没执行操作就挂掉了呢?或者抛出了异常?消息消费失败,但是RabbitMQ无从得知,这样消息就丢失了!
      因此,RabbitMQ有一个ACK机制。
      当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。不过这种回执ACK分两种情况:
      自动ACK: 消息一旦被接收,消费者自动发送ACK
      手动ACK: 消息接收后,不会发送ACK,需要手动调用

    • 使用场景:
      如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便
      如果消息非常重要,不容丢失。那么最好在消费完成后手动ACK,否则接收消息后就自动ACK

    Confirm 保证消息一定发送成功

    • 消息的确认,是指生产者投递消息后,如果 MQ 收到消息,则会给我们生产者一个应答。
    • 生产者进行接收应答,用来确定这条消息是否正常的发送到 MQ,这种方式也是消息的可靠性投递的核心保障!
    • 消息发送成功 和 失败, 会执行对应发送者的 回调方法!

    常见的消息 任务表:

    • 不是绝对的,这个消息表根据实际开发中更改即可!

    task_his.sql

    DROP TABLE IF EXISTS `task_his`;
    
    CREATE TABLE `task_his` (
      `id` varchar(32) NOT NULL COMMENT '任务id',
      `create_time` datetime DEFAULT NULL,
      `update_time` datetime DEFAULT NULL,
      `delete_time` datetime DEFAULT NULL,
      `task_type` varchar(32) DEFAULT NULL COMMENT '任务类型',
      `mq_exchange` varchar(64) DEFAULT NULL COMMENT '交换机名称',
      `mq_routingkey` varchar(64) DEFAULT NULL COMMENT 'routingkey',
      `request_body` varchar(512) DEFAULT NULL COMMENT '任务请求的内容',
      `version` int(10) DEFAULT '0' COMMENT '乐观锁版本号',
      `status` varchar(32) DEFAULT NULL COMMENT '任务状态',
      `errormsg` varchar(512) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    • 任务 创建时间 更新时间 删除时间 要操作MQ 交换机 队列信息!
    • 为方式分布式多服务 version 设置乐观锁版本号!

    Spring Task定时任务

    • 依赖:
    • 在Spring boot启动类上添加注解:@EnableScheduling
    • 任务类
    • Quartz 是一个异步任务调度框架,功能丰富,可以实现按日历调度

    定时任务类:

    • 仅供参考…

    MessageTaskJob.Java

    @Component
    public class MessageTaskJob {
    
        @Autowired
        private TbTaskService taskService;     //消息表业务对象!
    
        @Scheduled(cron = "0/30 * * * * ?")    //定时每三十秒扫描一次 消息表!
        public void showTask() {
            System.out.println("查询任务数据!");
            try {
                //获取一分钟前消息表数据!
                List<TbTask> list = taskService.getBeforTaskList();
    
                //循环变量发送MQ消息...
                for (TbTask tbTask : list) {
                    //使用乐观锁解决高并发下的信息发送...后面解释!
                    if (taskService.updateVersionLock(tbTask.getId(), tbTask.getVersion()) > 0) {
                        //发送MQ...
                        taskService.publishTaskMessage(tbTask);
                        //发送之后修改,当前 订单消息表的记录时间..当前时间即可!
                            //因为定时会循环,如果消息发送失败..则直接下次在轮询重新发送即可!
                        taskService.updateTaskUpdateTime(tbTask.getId());
                        System.out.println("发送消息并,修改时间!");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    • 修改时间,是为了, 防止消息发送失败等原因, 将时间修改为当前时间,定时操作执行在次发送... 确保最终一致性!
    • 为啥MQ 存在消息确认机制,还要这么做.
      不同的人不同的写法… 反之最终要发到 mq 上就ok了…
      这里将时间重排,重新定时发送 个人觉得为了公平… 你去银行排队办理业务,缺少文件回去办理…回来了当然要重新排队.

    Mybatis sql参考

        <!-- 获取一分钟前消息表的所有数据! -->
        <select id="getBeforTaskList" resultType="com.zb.entity.TbTask">
            select
            id as id,
            create_time as createTime,
            update_time as updateTime,
            delete_time as deleteTime,
            task_type as taskType,getBeforTaskList
            mq_exchange as mqExchange,
            mq_routingkey as mqRoutingkey,
            request_body as requestBody,
            status as status,
            errormsg as errormsg,
            version as version
            from tb_task
             WHERE TIMESTAMPDIFF(MINUTE,update_time, NOW())>1
        </select>
    
        <!-- 发送消息成功更改时间... -->
        <update id="updateNowTime" >
            update tb_task set update_time =now() where id=#{id}
        </update>
        <!-- 乐观锁:多线程情况下防止,统一消息发送多次处理...
                根据 id version版本 来进行修改..
        -->
        <update id="updateVersioLock">
            update tb_task set version =#{version}+1 where id=#{id} and version=#{version}
        </update>
    

    乐观锁:解决分布式锁.

    • 考虑订单服务将来会集群部署
    • 为了避免任务在 定时任务 内重复执行,这里使用乐观锁
      A B 线程执行任务都查到了 消息集合 A 发送了任务1 B 也发送了任务1 重复操作!
    • 乐观锁处理:
      A B线程都进入方法获取到 消息集合  A 先执行并带着版本号+id去给版本+1 B因为查的 消息集合并不是最新的id+版本号去修改影响行数小于0 不执行发送任务!

    但如果:A线程执行特别快修改了版本,但是B执行慢才查到,获取了最新的 消息集合

    • 就悲剧了…

    • 所以,可以在A修改版本号同时,修改当前时间…

    • 这样:B无论执行快慢都避免了重复操作!
      快: 因为版本 id 修改不了,影响行数不大于 0
      慢: 因为时间更改了,直接就获取不到最新的数据了…

    • 这只是我的个人想法: 实际开发另算根据场景来定~


    事务消息 RocketMQ [alibaba提供MQ技术]

    • 并不了解…但是听说过。后面准备学习!
    展开全文
  • 分布式事务概述

    千次阅读 2020-05-07 13:16:11
    RocketMQ官网介绍中这样描述RocketMQ的事务消息“消息队列 RocketMQ 版提供类似 X/Open XA 的分布式事务功能,通过消息队列 RocketMQ版事务消息能达到...那么剩下的问题就是理解出现了分歧,本文的目的就是在于解决分布

    概述


           RocketMQ官网介绍中这样描述RocketMQ的事务消息“消息队列 RocketMQ 版提供类似 X/Open XA 的分布式事务功能,通过消息队列 RocketMQ版事务消息能达到分布式事务的最终一致”。这段描述给我带来的困惑一点都不比出门没带手机更让我难受的多。我的逻辑回路里面一个高可用的分布式服务是无法满足分布式事务的一致性。因为消息传递过程具有不可靠性,所以分布式服务要做到每个环节都满足事务的ACID,最终事务也满足ACID是不可能的。那么剩下的问题就是理解出现了分歧,本文的目的就是在于解决分布式事务方面理解出现的偏差。

    一、事务简介


           事务是一个完整的工作单元。

           事务(Transaction)起源于数据库操作理论,在关系数据库中,一个事务由一组SQL语句组成。在《企业应用架构模式》中,事务是实现业务的一系列工作步骤。但是不管什么场景,事务都应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性,以数据库事务为例,ACID具体包含以下几个方面:
     原子性(atomicity):事务是一系列不可分割的操作的集合,事务中包括的所有操作要么全部执行成功,要么全部执行失败。
     一致性(consistency):事务是使数据从一个状态变到另一个状态过程中数据整体完整保持一致性。
     隔离性(isolation):事务的执行彼此独立互不干扰,隔离性又分为四个级别:读未提交(read uncommitted)、读已提交(read committed,解决脏读)、可重复读(repeatable read,解决虚读)、串行化(serializable,解决幻读)。
     持久性(durability):事务一旦提交,它对数据库中数据的改变就应该是永久性的。

            任何事务机制在实现时,都应该考虑事务的ACID特性,包括:本地事务、分布式事务,即使不能都很好的满足,也要考虑支持到什么程度。

      
    二、本地事务


            大多数场景下,我们的应用都只需要操作单一的数据库,这种情况下的事务称之为本地事务(Local Transaction)。本地事务的ACID特性是数据库直接提供支持。

    三、分布式事务


             分布式事务就是为了保证不同资源服务器的数据一致性。一个事务的执行对所有资源服务器的操作要么全部成功,要么全部失败。一个分布式事务可以分为全局事务,
    典型的分布式事务场景:
    1、跨库事务
     跨库事务指的是,一个应用某个功能需要操作多个库,不同的库中存储不同的业务数据。
    2、分布式数据库
    3、分库分表
    通常一个库数据量比较大或者预期未来的数据量比较大,都会进行水平拆分,也就是分库分表。
    4、业务服务化
          应用功能以对外服务的方式发布,并将这些服务之间通过接口和协议联系起来,构建完整的业务服务,这就是业务服务化。业务服务化中应用功能之间独立操作数据库,或者会操作多个数据库。

           通常不同的应用功能都会操作不同的数据库,同一个应用多次操作同一个数据库,同一个应用多次操作不同数据库等等,都需要保证事务的对多个数据库的操作要不都成功,要不都失败,实际上这可能是最典型的分布式事务场景。当然一个典型的分布式事务场景并不要求一定要有数据库操作,重要的是数据持久化。如果没有数据持久化,就相当于做一件事情有起点有过程没有终点。对比事务的概念这样的事务是不完整的。

    四、X/Open DTP模型与XA规范

    X/Open国际联盟有限公司是一个欧洲基金会。他是一个国际性的自由开放组织,主要的目标是促进对UNIX语言、接口、网络和应用的开放式系统协议的制定。就分布式事务处理(Distributed Transaction Processing,简称DTP)而言,X/Open主要提供了以下参考文档:
       DTP 参考模型: <<Distributed Transaction Processing: Reference Model>>
       DTP XA规范: << Distributed Transaction Processing: The XA Specification>>

    4.1 DTP模型
          在X/Open中,DTP是一种软件架构模型,他允许多个应用程序共享多个资源管理器提供的资源,并允许应用之间满足全局事务的规范。在DTP参考模型第三版中指出,DTP模型包含应用程序、资源管理器、事务管理器、通信资源管理器、通信协议五个基础部分。

    应用程序 (an Application Program,简称AP):应用程序定义了事务边界(即事务的开始和结束)并指定了构成事务的操作(即事务对资源做的处理)。
    资源管理器(Resource Managers ,简称RMs):资源管理器提供对资源的管理和访问方式,如数据库,文件系统等。
    事务管理器(a Transaction Manager 简称TM):负责给所有的事务分配唯一标识,监控事务的执行进度,并负责事务的提交、回滚等。之所以是所有事务,因为分布式环境中,事务包含一个全局事务和若干分支事务组成。
    通信资源管理器(Communication Resource Managers,简称CRMs):控制同TM域或者跨TM域的分布式应用之间的通信。
    通信协议(a communication protocol,简称CP):为分布式应用或者支持CRMs的服务提供底层通信服务。

            参照X/Open DTP模型列举了一种可移植的高级语言(HTL,high-level TP language),一系列可移植的接口和便利的系统级接口,具体包括:
    •应用程序源代码的可移植性
    •TMs、RMs和CRMs的可互换性
    •同一全局事务中不同TMs、RMs和CRMs的互操作性

    2、模型实例(Instance of the Model)

    一个DTP模型实例至少包含三个部分:一个应用程序(AP),一个事务管理器(TM),多个资源管理器(RMs)。

    类比一下华为分布式数据库中间件DDM,用户应用就是AP,DDM就是一个事务管理器TM,数据就是多个资源管理器(RMs)。应用程序AP需要操作多个数据库RMs,通过DDM也就是(TM)声明一个全局事务,DDM通过监控所有数据库(RMs),来协调不同数据库上的提交和回滚。


    补充:这里我们可以发现,数据库(RMs)本身也有自己的事务管理器(TM),这是由于TMs、RMs和CRMs的可互换性,DTP模型规定了要有这些组成部分,但是组成部分之间是单独实现还是融合实现并没有规定。

    3、事务管理器作用域 (TM domain)

    一个TM域由一个或多个使用相同TM的实例组成.对于在TM域中运行的所有应用程序,使用公共的事务管理器。类比我们分库分表场景,所有的库表使用的都是同样的事务管理策略。公共TM使用逻辑共享的数据用于全局事务管理的结构和日志。

    4.通信资源管理器(CRMs)

    在跨应用的分布式模型中,比如大部分SOA服务,为了满足不同服务之间的事务管理,每个DTP模型实例需要引入一个通信资源管理器(CRM),多个实例之间的CRM构成通信管理器组(CRMs)。


     CRM具备事务传播能力,用于满足跨域应用或者同域应用之间的通信,CRMs通过支持以下接口来提供全局事务:
     1.在AP和CRM之间使用的通信范型(TxRPC、XATMI或CPI-C,版本2)
     2.在TM与CRM之间使用XA+ 通信
     3.CRM和OSI TP之间的XAP-TP通信。

    5.全局事务树形结构(Global Transaction Tree Structure)
    在X/Open的DTP模型中,提出对分布式应用操作的全局事务采用树结构进行管理的概念。

    当两个实例之间发生分布式通信时,他们有一种上级和下级的关系,全局事务中发出请求的实例称为上级实例,被请求的实例称为从属实例,没有上级实例的实例称为根实例。
    一个全局事务包含一个或者多个事务分支,每个事务分支提现支持由TM和一组参与的RMs参与的全局事务中的一部分工作。在两个事务通信过程中,由一个上级事务服务管理协调同级的下级事务,并逐级上报给上级事务,直到根事务,从而实现全局事务监管。

    6 XA规范
    XA提供了DTP组件之间通信交互的规范。(Common Application Environment,CAE)通用应用环境和。下图展示了一个典型的DTP模型中,应用程序调用事务管理器构建事务的过程。图中方框代表应用组件,箭头代表调用方向。在一个工作流程中可能存在多个DTP实例,XA规范并不要求所有组件保持独立,也不需要单独的线程去控制。也就是说DTP模型中的组件并没有一个一成不变的角色。比如,一个事务管理器可能用资源管理器来完成事务监管的工作。
    6.1接口规范

    6.2事务完成和恢复
    参考OSI DTP规范(模型),TMs和RMs使用假定回滚的两阶段提交模式。
    第一阶段:TM要求所有的RMs准备提交(或准备)事务分支。
    这将询问RM是否能够保证其提交事务分支的能力。如果一个RM可以提交它的工作,它稳定地记录它需要完成的工作,然后对TM做出应答。如果失败,RM自己会回滚,并放弃当前分支事务信息。
    第二阶段:TM向所有RMs发出一个实际请求来提交或回滚事务分支。所有的RMs提交或回滚对共享资源的更改,然后将状态返回给TM,然后,TM可以放弃其关于全局事务的知识。

    五、经典的分布式系统理论-CAP

    2000年7月,加州大学伯克利分校的Eric Brewer教授在ACM PODC会议上提出CAP猜想。Brewer认为在设计一个大规模的分布式系统时会遇到三个特性:一致性(consistency)、可用性(Availability)、分区容错(partition-tolerance),而一个分布式系统最多只能满足其中的2项。2年后,麻省理工学院的Seth Gilbert和Nancy Lynch从理论上证明了CAP。之后,CAP理论正式成为分布式计算领域的公认定理。 
      一致性(Consistency)    所有节点在同一时间访问到的数据完全一致
      可用性(Availability)   即服务整体一直可用,能及时对每一个请求能做出响应。
      分区容错性(Partition Tolerance)   当集群中的某些结点无法联系时仍能正常提供服务

    总结: 既然一个分布式系统无法同时满足一致性、可用性、分区容错性三个特点,我们就需要做出相应的取舍。由于网络问题是分布式系统必然要遇到的问题,也就是说分布式系统必须解决分区容错性,因此系统架构师往往需要把精力花在如何根据业务特点在C(一致性)和A(可用性)之间寻求平衡。目前大部分互联网公司都选择采用基于BASE理论的柔性事务,选择可用性和分区容错性,舍弃强一致性。

    参考资料:

     http://www.tianshouzhi.com/api/tutorials/distributed_transaction/383

    https://pubs.opengroup.org/onlinepubs/9294999599/toc.pdf

    https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf

     

     

    展开全文
  • 分布式事务简述

    千次阅读 2017-03-27 18:56:26
    国际开放标准组织Open Group定义了DTS(分布式事务处理模型),模型中包含4个角色:应用程序、事务管理器、资源管理器、通信资源管理器四部分。事务处理器是统管全局的管理者,资源处理器和通信资源处理器是事务的...

    国际开放标准组织Open Group定义了DTS(分布式事务处理模型),模型中包含4个角色:应用程序、事务管理器、资源管理器、通信资源管理器四部分。事务处理器是统管全局的管理者,资源处理器和通信资源处理器是事务的参与者。

    J2EE规范也包含此分布式事务处理模型的规范,并在所有的AppServer中进行实现,J2EE规范中定义了TX协议和XA协议,TX协议定义应用程序与事务管理器之间的接口,而XA协议定义了事务管理器与资源处理器之间的接口,在过去,大家使用AppServer,例如:Websphere、Weblogic、Jboss等配置数据源的时候会看见类似XADatasource的数据源,这就是实现了DTS的关系型数据库的数据源。企业级开发JEE中,关系型数据库、JMS服务扮演资源管理器的角色,而EJB容器则扮演事务管理器的角色。

    下面我们就介绍两阶段提交协议三阶段提交协议以及阿里巴巴提出的TCC,它们都是根据DTS这一思想演变出来的。

    1. 两阶段提交协议

    上面描述的JEE的XA协议就是根据两阶段提交来保证事务的完整性,并实现分布式服务化的强一致性。

    两阶段提交协议把分布式事务分成两个过程,一个是准备阶段,一个是提交阶段,准备阶段和提交阶段都是由事务管理器发起的,为了接下来讲解方便,我们把事务管理器称为协调者,把资管管理器称为参与者。

    两阶段如下:

    1. 准备阶段:协调者向参与者发起指令,参与者评估自己的状态,如果参与者评估指令可以完成,参与者会写redo或者undo日志(这也是前面提起的Write-Ahead Log的一种),然后锁定资源,执行操作,但是并不提交
    2. 提交阶段:如果每个参与者明确返回准备成功,也就是预留资源和执行操作成功,协调者向参与者发起提交指令,参与者提交资源变更的事务,释放锁定的资源;如果任何一个参与者明确返回准备失败,也就是预留资源或者执行操作失败,协调者向参与者发起中止指令,参与者取消已经变更的事务,执行undo日志,释放锁定的资源

    两阶段提交协议成功场景示意图如下:


    两阶段提交协议

    我们看到两阶段提交协议在准备阶段锁定资源,是一个重量级的操作,并能保证强一致性,但是实现起来复杂、成本较高,不够灵活,更重要的是它有如下致命的问题:

    1. 阻塞:从上面的描述来看,对于任何一次指令必须收到明确的响应,才会继续做下一步,否则处于阻塞状态,占用的资源被一直锁定,不会被释放
    2. 单点故障:如果协调者宕机,参与者没有了协调者指挥,会一直阻塞,尽管可以通过选举新的协调者替代原有协调者,但是如果之前协调者在发送一个提交指令后宕机,而提交指令仅仅被一个参与者接受,并且参与者接收后也宕机,新上任的协调者无法处理这种情况
    3. 脑裂:协调者发送提交指令,有的参与者接收到执行了事务,有的参与者没有接收到事务,就没有执行事务,多个参与者之间是不一致的

    上面所有的这些问题,都是需要人工干预处理,没有自动化的解决方案,因此两阶段提交协议在正常情况下能保证系统的强一致性,但是在出现异常情况下,当前处理的操作处于错误状态,需要管理员人工干预解决,因此可用性不够好,这也符合CAP协议的一致性和可用性不能兼得的原理。

    2. 三阶段提交协议

    三阶段提交协议是两阶段提交协议的改进版本。它通过超时机制解决了阻塞的问题,并且把两个阶段增加为三个阶段:

    1. 询问阶段:协调者询问参与者是否可以完成指令,协调者只需要回答是还是不是,而不需要做真正的操作,这个阶段超时导致中止
    2. 准备阶段:如果在询问阶段所有的参与者都返回可以执行操作,协调者向参与者发送预执行请求,然后参与者写redo和undo日志,执行操作,但是不提交操作;如果在询问阶段任何参与者返回不能执行操作的结果,则协调者向参与者发送中止请求,这里的逻辑与两阶段提交协议的的准备阶段是相似的,这个阶段超时导致成功
    3. 提交阶段:如果每个参与者在准备阶段返回准备成功,也就是预留资源和执行操作成功,协调者向参与者发起提交指令,参与者提交资源变更的事务,释放锁定的资源;如果任何一个参与者返回准备失败,也就是预留资源或者执行操作失败,协调者向参与者发起中止指令,参与者取消已经变更的事务,执行undo日志,释放锁定的资源,这里的逻辑与两阶段提交协议的提交阶段一致

    三阶段提交协议成功场景示意图如下:


    三阶段提交协议

    然而,这里与两阶段提交协议有两个主要的不同:

    1. 增加了一个询问阶段,询问阶段可以确保尽可能早的发现无法执行操作而需要中止的行为,但是它并不能发现所有的这种行为,只会减少这种情况的发生
    2. 在准备阶段以后,协调者和参与者执行的任务中都增加了超时,一旦超时,协调者和参与者都继续提交事务,默认为成功,这也是根据概率统计上超时后默认成功的正确性最大

    三阶段提交协议与两阶段提交协议相比,具有如上的优点,但是一旦发生超时,系统仍然会发生不一致,只不过这种情况很少见罢了,好处就是至少不会阻塞和永远锁定资源。

    3. TCC

    上面两节讲解了两阶段提交协议和三阶段提交协议,实际上他们能解决"转账""下订单和扣库存"中的分布式事务的问题,但是遇到极端情况,系统会发生阻塞或者不一致的问题,需要运营或者技术人工解决。无论两阶段还是三阶段方案中都包含多个参与者、多个阶段实现一个事务,实现复杂,性能也是一个很大的问题,因此,在互联网高并发系统中,鲜有使用两阶段提交和三阶段提交协议的场景。

    阿里巴巴提出了新的TCC协议,TCC协议将一个任务拆分成Try、Confirm、Cancel,正常的流程会先执行Try,如果执行没有问题,再执行Confirm,如果执行过程中出了问题,则执行操作的逆操Cancel,从正常的流程上讲,这仍然是一个两阶段的提交协议,但是,在执行出现问题的时候,有一定的自我修复能力,如果任何一个参与者出现了问题,协调者通过执行操作的逆操作来取消之前的操作,达到最终的一致状态。

    可以看出,从时序上,如果遇到极端情况下TCC会有很多问题的,例如,如果在Cancel的时候一些参与者收到指令,而一些参与者没有收到指令,整个系统仍然是不一致的,这种复杂的情况,系统首先会通过补偿的方式,尝试自动修复的,如果系统无法修复,必须由人工参与解决。

    从TCC的逻辑上看,可以说TCC是简化版的三阶段提交协议,解决了两阶段提交协议的阻塞问题,但是没有解决极端情况下会出现不一致和脑裂的问题。然而,TCC通过自动化补偿手段,会把需要人工处理的不一致情况降到到最少,也是一种非常有用的解决方案,根据线人,阿里在内部的一些中间件上实现了TCC模式。

    我们给出一个使用TCC的实际案例,在秒杀的场景,用户发起下单请求,应用层先查询库存,确认商品库存还有余量,则锁定库存,此时订单状态为待支付,然后指引用户去支付,由于某种原因用户支付失败,或者支付超时,系统会自动将锁定的库存解锁供其他用户秒杀。

    TCC协议使用场景示意图如下:


    TCC

    总结一下,两阶段提交协议、三阶段提交协议、TCC协议都能保证分布式事务的一致性,他们保证的分布式系统的一致性从强到弱,TCC达到的目标是最终一致性,其中任何一种方法都可以不同程度的解决"转账"和"下订单和扣库存"的问题,只是实现的一致性的级别不一样而已,对于"同步超时"可以通过TCC的理念解决,如果同步调用超时,调用方可以使用fastfail策略,返回调用方的使用方失败的结果,同时调用服务的逆向cancel操作,保证服务的最终一致性。

    4.TCC的赘述

    TCC是三个英文单词的首字母缩写而来,TCC分别对应Try、Confirm和Cancel三种操作

    这三种操作的业务含义如下:

    • Try:尝试执行业务
      完成所有业务检查(一致性)
      预留必须业务资源(准隔离性)
    • Confirm:确认执行业务
      真正执行业务
      不做任何业务检查
      只使用Try阶段预留的业务资源
    • Cancel:取消执行业务
      释放Try阶段预留的业务资源

    稍稍对照下关系型数据库事务的三种操作:DML、Commit和Rollback,会发现和TCC有异曲同工之妙。在一个跨应用的业务操作中,
    Try操作是先把多个应用中的业务资源预留和锁定住,为后续的确认打下基础,类似的,DML操作要锁定数据库记录行,持有数据库资源;
    Confirm操作是在Try操作中涉及的所有应用均成功之后进行确认,使用预留的业务资源,和Commit类似;
    而Cancel则是当Try操作中涉及的所有应用没有全部成功,需要将已成功的应用进行取消(即Rollback回滚)。
    其中Confirm和Cancel操作是一对反向业务操作。

    一个完整的TCC事务参与方包括三部分:

    • 主业务服务:主业务服务为整个业务活动的发起方,如前面提到的组合支付场景,支付系统即是主业务服务。
    • 从业务服务:从业务服务负责提供TCC业务操作,是整个业务活动的操作方。从业务服务必须实现Try、Confirm和Cancel三个接口,供主业务服务调用。
      由于Confirm和Cancel操作可能被重复调用,故要求Confirm和Cancel两个接口必须是幂等的。前面的组合支付场景中的余额系统和红包系统即为从业务服务。
    • 业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录维护TCC全局事务的事务状态和每个从业务服务的子事务状态,并在业务活动提交时确认所有的TCC型操作的confirm操作,在业务活动取消时调用所有TCC型操作的cancel操作。

    可见整个TCC事务对于主业务服务来说是透明的,其中业务活动管理器和从业务服务各自干了一部分工作。

    TCC事务的优点如下:
    解决了跨应用业务操作的原子性问题,在诸如组合支付、账务拆分场景非常实用。 TCC实际上把数据库层的二阶段提交上提到了应用层来实现,对于数据库来说是一阶段提交,规避了数据库层的2PC性能低下问题。

    TCC事务的缺点,主要就一个:
    TCC的Try、Confirm和Cancel操作功能需业务提供,开发成本高。 当然,对TCC事务的这个缺点是否是缺点,是一个见仁见智的事情。

    一个案例理解 TCC说实话,TCC的理论有点让人费解。故接下来将以账务拆分为例,对TCC事务的流程做一个描述,希望对理解TCC有所帮助。 账务拆分的业务场景如下,分别位于三个不同分库的帐户A、B、C,A和B一起向C转帐共80元:分布式事务之说说TCC事务

    a、Try:尝试执行业务。 完成所有业务检查(一致性):检查A、B、C的帐户状态是否正常,帐户A的余额是否不少于30元,帐户B的余额是否不少于50元。 预留必须业务资源(准隔离性):帐户A的冻结金额增加30元,帐户B的冻结金额增加50元,这样就保证不会出现其他并发进程扣减 了这两个帐户的余额而导致在后续的真正转帐操作过程中,帐户A和B的可用余额不够的情况。

    b、Confirm:确认执行业务。 真正执行业务:如果Try阶段帐户A、B、C状态正常,且帐户A、B余额够用,则执行帐户A给账户C转账30元、帐户B给账户C转账50元的 转帐操作。 不做任何业务检查:这时已经不需要做业务检查,Try阶段已经完成了业务检查。 只使用Try阶段预留的业务资源:只需要使用Try阶段帐户A和帐户B冻结的金额即可。

    c、Cancel:取消执行业务 释放Try阶段预留的业务资源:如果Try阶段部分成功,比如帐户A的余额够用,且冻结相应金额成功,帐户B的余额不够而冻结失败,则需要对帐户A做Cancel操作,将帐户A被冻结的金额解冻掉。


    原文地址: 

    http://wuwenliang.net/2017/03/25/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E4%B9%8B%E8%81%8A%E8%81%8ATCC/

    http://www.jianshu.com/p/1156151e20c8

    展开全文
  • oracle事务概述

    千次阅读 2015-10-14 11:03:36
    oracle确保事务完整性的机制是撤销段和重做日志文件的组合:此机制无疑是迄今为止开发的任何数据库中的翘楚,而且完全符合数据处理的国际标准。虽然其他数据库供应商能够通过使用自己的机制遵循相同的标准,但是却...
  • Oracle事务处理

    万次阅读 2015-11-22 17:44:12
    oracle事务处理 什么是事务事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败。 如:网上转账就是典型的要用事务来处理,用以保证数据的一致性。   事务和锁 ...
  • Spring 及SpringMVC的理解

    万次阅读 多人点赞 2014-11-07 09:37:14
    Spring是一个轻型容器...在此基础之上,Spring提供了AOP(Aspect-Oriented Programming, 面向层面的编程)的实现,用它来提供非管理环境下申明方式的事务、安全等服务;Bean工厂的扩展ApplicationContext更加方便
  • 事务理论的角度来看,可以把事务分为以下五种类型: 扁平事务(Flat Transactions) 带有保存点的扁平事务(Flat Transactions with Savepoints) 链事务(Chained Transactions) 嵌套事务(Nested Transactions...
  • 关于JSR标准的理解

    千次阅读 2016-05-03 18:50:51
    JSR是Java Specification Requests的缩写,意思是“Java 规范提案”。是指向JCP(Java Community ...简单的就是jsr是java开发者以及授权者指定的标准,而java开发者以及授权者形成一个jcp国际组织。职能是指定java标准。
  • ,是一种编程技术,它允许程序员横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。 AOP  的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中。  AOP  和  IOC ...
  • Java面试之五大框架的理解

    千次阅读 2018-08-29 11:51:15
    说说你springMVC框架的理解? 简要口述(如果感觉说的少可以在完整答案里面挑几条说) Springmvc就是spring框架的一个模块,它是一个基于mvc设计思想的前端web层框架,主要作用就是前端请求进行处理。 ...
  • IOC,AOP的理解

    万次阅读 多人点赞 2016-08-26 16:33:54
    比如登陆时候在进入登录页面前写入日志,登录以后查看cookie等类似的操作,很常用的,尤其是跟数据库有关的,或者跟支付有关的程序肯定会在每一步前面插入日志,还有某些国际化项目会在每次跳转时候都转换字符集之类...
  • 在讲分布式事务之前,我们需要先了解事务 1: 1.1事务的概念: 事务:指作为单个逻辑工作单元执行的一系列操作,这些操作要么同时成功,要么同时失败(同生共死). 1.2本地事务(Local Transaction) 概念:本地事务...
  • VOIP SIP 事务的概念

    2016-03-23 21:31:51
    该文章讲述了理解SIP事务的概念. SIP协议中,比较有特点的就是SIP事务了。那么想要理解SIP事务的概念,我们还需要了解sip请求的一些内容。 sip事务的概念:一个sip请求以及由它触发的一系列应答(包括临时应答和一个...
  • 简单描述AOP和IOC的理解

    千次阅读 2019-05-10 19:47:28
    aop方式就理解起来就简单了,其方式很类似j2ee中的filter,就是在程序正常的业务流中间像切面一样插入很多其他需要执行的代码,比如登陆时候在进入登录页面前写入日志,登录以后查看cookie等类似的操作,很常用的,...
  • 浅谈事务、COM+及分布式事务

    千次阅读 2009-06-11 17:42:00
    浅谈事务、COM+及分布式事务 目录1 什么是事务及特性...................................................................................................................................... 21.1 什么是...
  • 数据库事务ACID原则学习分享

    千次阅读 2019-05-12 16:12:40
    本人结合自己技术的理解,努力以通俗易懂的内容帮助大家了解技术的基本原理,内容仅供参考,不对或不完善的地方请大家指教,感谢关注! 一、事务概念的引入 当今,信息化技术非常发达的时代,我们通过手机上的...
  • 而在互联网时代,一致性的含义远远超出了它原有的含义,在我们讨论互联网时代的一致性之前,我们先了解一下互联网时代的特点,互联网时代信息量巨大、需要计算能力巨大,不但用户响应速度要求快,而且吞吐量指标也...
  • 第6章 数据库管理之事务

    热门讨论 2014-09-24 09:35:00
    事务是构成单一国际工作单元的操作几个,要么完整地执行,要不完全不执行。不论发生何种情况,DBS必须保证事务能正确,完整地执行。 由事务的概念我们可以知道,DBS就是来执行事务的,而一个事务并不是一个单一...
  • 分布式事务综述(XA, TCC)

    千次阅读 2018-03-23 14:05:16
     最早的分布式事务模型是 X/Open 国际联盟提出的 X/Open Distributed Transaction Processing(DTP)模型,也就是大家常说的 X/Open XA 协议,简称XA 协议。     DTP 模型中包含一个全局事务管理器(TM,...
  • 主要内容包括:TCP事务协议,即T/TCP,这是TCP的扩展,使客户-服务器事务更快、更高效和更可靠;TCP/IP应用,主要是HTTP和NNTP;UNIX域协议,这些协议提供了进程之间通信的一种手段。当客户与服务器进程在同一台...
  • 目录 1.分布式事务基础理论 1.1.CAP理论 1.2.BASE理论 2.分布式事务解决方案之2PC(两阶段提交) ...因此,分布式事务需要更进一步的理论支持,接下来,我们先来学习一下分布式事务的CAP理论。 1.1.CAP理论 C..
  • 分布式事务中间件你知道哪些?

    千次阅读 2019-11-06 00:00:00
    在分布式数据库、云原生数据库、NewSQL 等名词在数据库领域层出不穷的当今,变革——在这个相对稳定的领域...水平拆分使得分布式事务的重要性,较之垂直拆分的业务系统进一步提升。另外,弹性扩(缩)容、HTAP 等概...
  • 注意,如下是本章目录,本文节选9.1~9.2.2 9.3.3.4~最后 为了方便读者深入学习,本系列连载都会将作者研究过 程中所学习的参考文献列出来 第九章 深入理解GPS本章主要内容介绍GPS基础知识;介绍Andr
  • 分布式事务 1 基础概念 1.1 什么是事务 什么是事务?举个生活中的例子:你去小卖铺买东西,“一手交钱,一手交货”就是一个事务的例子,交钱和交货必 须全部成功,事务才算成功,任一个活动失败,事务将撤销所有已...
  • Spring IOC、AOP与事务

    千次阅读 2020-09-09 17:37:30
    单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候,这个对象的非静态成员变量的写操作会存在线程安全问题。 常见的有两种解决办法: 在Bean对象中尽量避免定义可变的成员变量(不太现实)。 在...
  • 分布式事务 1 基础概念 1.1 什么是事务 什么是事务?举个生活中的例子:你去小卖铺买东西,“一手交钱,一手交货”就是一个事务的例子,交钱和交货必 须全部成功,事务才算成功,任一个活动失败,事务将撤销所有已...
  • 理解专业程序员

    千次阅读 2014-11-21 10:36:21
    理解专业程序员 Understanding the Professional Programmer   杰拉尔德 温伯格      如果你是一个程序员,或是程序员的管理者,或者处于任何和程序员紧密...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,671
精华内容 9,468
关键字:

对国际事务的理解