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

    2020-10-07 13:53:02
    如何实现两个分布式服务(订单服务、库存服务)共同完成一件事即订单支付成功自动自动减库存,这里 的关键是如何保证两个分布式服务的事务的一致性。 尝试解决上边的需求,在订单服务中远程调用减库存接口,伪代码...

    问题描述
    用户支付完成会将支付状态及订单状态保存在订单数据库中,由订单服务去维护订单数据库。由库存服务去维护库存数据库的信息。下图是系统结构图:

    在这里插入图片描述

    如何实现两个分布式服务(订单服务、库存服务)共同完成一件事即订单支付成功自动减库存,这里
    的关键是如何保证两个分布式服务的事务的一致性。
    尝试解决上边的需求,在订单服务中远程调用减库存接口,伪代码如下:

    订单支付结果通知方法{

    ​ 更新支付表中支付状态为“成功”。 ​
    远程调用减库存接口减库存。

    上边的逻辑说明:
    1、更新支付表状态为本地数据库操作。
    2、远程调用减库存接口为网络远程调用请求。
    3、为保存事务上边两步操作由spring控制事务,当遇到Exception异常则回滚本地数据库操作。
    问题如下:
    1、如果更新支付表失败则抛出异常,不再执行远程调用,此设想没有问题。
    2、如果更新支付表成功,网络远程调用超时会拉长本地数据库事务时间,影响数据库性能。
    3、如果更新支付表成功,远程调用减库存成功(减库存数据库commit成功),最后更新支付表commit失败,此时出现操作不一致。
    上边的问题涉及到分布式事务控制。

    什么是分布式事务

    什么是分布式系统:

    部署在不同结点上的系统通过网络交互来完成协同工作的系统。
    比如:充值加积分的业务,用户在充值系统向自己的账户充钱,在积分系统中自己积分相应的增加。充值系统和积分系统是两个不同的系统,一次充值加积分的业务就需要这两个系统协同工作来完成。

    什么是事务:

    事务是指由一组操作组成的一个工作单元,这个工作单元具有原子性(atomicity)、一致性(consistency)、隔
    离性(isolation)和持久性(durability)。
    原子性:执行单元中的操作要么全部执行成功,要么全部失败。如果有一部分成功一部分失败那么成功的操作要全
    部回滚到执行前的状态。

    一致性:执行一次事务会使用数据从一个正确的状态转换到另一个正确的状态,执行前后数据都是完整的。

    隔离性:在该事务执行的过程中,任何数据的改变只存在于该事务之中,对外界没有影响,事务与事务之间是完全的隔离的。只有事务提交后其它事务才可以查询到最新的数据。

    持久性:事务完成后对数据的改变会永久性的存储起来,即使发生断电宕机数据依然在。

    什么是本地事务:

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

    什么是分布式事务:

    在分布式系统中一次操作由多个系统协同完成,这种一次事务操作涉及多个系统通过网络协同完成的过程称为分布式事务。这里强调的是多个系统通过网络协同完成一个事务的过程,并不强调多个系统访问了不同的数据库,即使多个系统访问的是同一个数据库也是分布式事务,如下图:

    在这里插入图片描述

    另外一种分布式事务的表现是,一个应用程序使用了多个数据源连接了不同的数据库,当一次事务需要操作多个数据源,此时也属于分布式事务,当系统作了数据库拆分后会出现此种情况。

    在这里插入图片描述
    分布式事务有哪些应用场景:

    1)电商系统中的下单扣库存
    电商系统中,订单系统和库存系统是两个系统,一次下单的操作由两个系统协同完成
    2)金融系统中的银行卡充值
    在金融系统中通过银行卡向平台充值需要通过银行系统和金融系统协同完成。
    3)教育系统中下单选课业务
    在线教育系统中,用户购买课程,下单支付成功后学生选课成功,此事务由订单系统和选课系统协同完成。
    4) SNS系统的消息发送
    在社交系统中发送站内消息同时发送手机短信,一次消息发送由站内消息系统和手机通信系统协同完成。

    如何进行分布式事务控制

    CAP理论
    CAP理论是分布式事务处理的理论基础:分布式系统在设计时只能在一致性(Consistency)、可用性(Availability)、分区容忍性(PartitionTolerance)中满足两种,无法兼顾三种。

    在这里插入图片描述

    一致性(Consistency):服务A、B、C三个结点都存储了用户数据, 三个结点的数据需要保持同一时刻数据一致性。
    可用性(Availability):服务A、B、C三个结点,其中一个结点宕机不影响整个集群对外提供服务,如果只有服务A结点,当服务A宕机整个系统将无法提供服务,增加服务B、C是为了保证系统的可用性。
    分区容忍性(Partition Tolerance):分区容忍性就是允许系统通过网络协同工作,分区容忍性要解决由于网络分区导致数据的不完整及无法访问等问题。

    分布式系统不可避免的出现了多个系统通过网络协同工作的场景,结点之间难免会出现网络中断、网延延迟等现
    象,这种现象一旦出现就导致数据被分散在不同的结点上,这就是网络分区

    分布式系统如果兼顾CAP:
    在保证分区容忍性的前提下一致性和可用性无法兼顾,如果要提高系统的可用性就要增加多个结点,如果要保证数据的一致性就要实现每个结点的数据一致,结点越多可用性越好,但是数据一致性越差。
    所以,在进行分布式系统设计时,同时满足“一致性”、“可用性”和“分区容忍性”三者是几乎不可能的。
    CAP有哪些组合方式?

    CA:放弃分区容忍性,加强一致性和可用性,关系数据库按照CA进行设计。
    AP:放弃一致性,加强可用性和分区容忍性,追求最终一致性,很多NoSQL数据库按照AP进行设计。
    说明:这里放弃一致性是指放弃强一致性,强一致性就是写入成功立刻要查询出最新数据。追求最终一致性是指允许暂时的数据不一致,只要最终在用户接受的时间内数据 一致即可。
    CP:放弃可用性,加强一致性和分区容忍性,一些强一致性要求的系统按CP进行设计,比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。说明:由于网络问题的存在CP系统可能会出现待等待超时,如果没有处理超时问题则整理系统会出现阻塞。

    总结

    ​ 在分布式系统设计中AP的应用较多,即保证分区容忍性和可用性,牺牲数据的强一致性(写操作后立刻读取到最新数据),保证数据最终一致性。比如:订单退款,今日退款成功,明日账户到账,只要在预定的用户可以接受的时间内退款事务走完即可。

    分布式事务一致性解决方案

    两阶段提交协议(2PC)

    为解决分布式系统的数据一致性问题出现了两阶段提交协议(2 Phase Commitment Protocol),两阶段提交由协调者和参与者组成,共经过两个阶段和三个操作,部分关系数据库如Oracle、MySQL支持两阶段提交协议,本节讲解关系数据库两阶段提交协议。

    参考:2PC:https://en.wikipedia.org/wiki/Two-phase_commit_protocol

    2PC协议流程图

    在这里插入图片描述

    1)第一阶段:准备阶段(prepare)
    协调者通知参与者准备提交订单,参与者开始投票。
    参与者完成准备工作向协调者回应Yes|NO。
    2)第二阶段:提交(commit)/回滚(rollback)阶段
    协调者根据参与者的投票结果发起最终的提交指令。
    如果有参与者没有准备好则发起回滚指令。

    一个下单减库存的例子:

    在这里插入图片描述

    1、应用程序连接两个数据源。
    2、应用程序通过事务协调器向两个库发起prepare,两个数据库收到消息分别执行本地事务(记录日志),但不提交,如果执行成功则回复yes,否则回复no。
    3、事务协调器收到回复,只要有一方回复no则分别向参与者发起回滚事务,参与者开始回滚事务。
    4、事务协调器收到回复,全部回复yes,此时向参与者发起提交事务。如果参与者有一方提交事务失败则由事务协调器发起回滚事务。

    2PC的优点:实现强一致性,部分关系数据库支持(Oracle、MySQL等)。
    缺点:整个事务的执行需要由协调者在多个节点之间去协调,增加了事务的执行时间,性能低下。
    解决方案:springboot+Atomikos or Bitronix

    3PC主要是解决协调者与参与者通信阻塞问题而产生的,它比2PC传递的消息还要多,性能不高。详细参考3PC:
    https://en.wikipedia.org/wiki/Three-phase_commit_protocol

    事务补偿 TCC

    TCC事务补偿是基于2PC实现的业务层事务控制方案,它是Try、Confirm和Cancel三个单词的首字母,含义如下:
    1、Try 检查及预留业务资源完成提交事务前的检查,并预留好资源。
    2、Confirm确定执行业务操作对try阶段预留的资源正式执行。
    3、Cancel取消执行业务操作对try阶段预留的资源释放。

    下边用一个下单减库存的业务为例来说明:

    在这里插入图片描述

    1、Try
    下单业务由订单服务和库存服务协同完成,在try阶段订单服务和库存服务完成检查和预留资源。
    订单服务检查当前是否满足提交订单的条件(比如:当前存在未完成订单的不允许提交新订单)。
    库存服务检查当前是否有充足的库存,并锁定资源。
    2、Confirm
    订单服务和库存服务成功完成Try后开始正式执行资源操作。
    订单服务向订单写一条订单信息。
    库存服务减去库存。
    3、Cancel
    如果订单服务和库存服务有一方出现失败则全部取消操作。
    订单服务需要删除新增的订单信息。
    库存服务将减去的库存再还原。
    优点:最终保证数据的一致性,在业务层实现事务控制,灵活性好。
    缺点:开发成本高,每个事务操作每个参与者都需要实现try/confirm/cancel三个接口。

    注意:TCC的try/confirm/cancel接口都要实现幂等性,在为在try、confirm、cancel失败后要不断重试。

    什么是幂等性?
    幂等性是指同一个操作无论请求多少次,其结果都相同。 幂等操作实现方式有:
    1、操作之前在业务方法进行判断如果执行过了就不再执行。
    2、缓存所有请求和处理的结果,已经处理的请求则直接返回结果。
    3、在数据库表中加一个状态字段(未处理,已处理),数据操作时判断未处理时再处理。

    消息队列实现最终一致性

    本方案是将分布式事务拆分成多个本地事务来完成,并且由消息队列异步协调完成,如下图:
    下边以下单减少库存为例来说明:

    在这里插入图片描述

    可以把MQ去掉不使用MQ

    1、订单服务和库存服务完成检查和预留资源。
    2、订单服务在本地事务中完成添加订单表记录和添加“减少库存任务消息”。
    3、由定时任务根据消息表的记录发送给MQ通知库存服务执行减库存操作。
    4、库存服务执行减少库存,并且记录执行消息状态(为避免重复执行消息,在执行减库存之前查询是否执行过此消息)。
    5、库存服务向MQ发送完成减少库存的消息。
    6、订单服务接收到完成库存减少的消息后删除原来添加的“减少库存任务消息”。
    实现最终事务一致要求:预留资源成功理论上要求正式执行成功,如果执行失败会进行重试,要求业务执行方法实现幂等。

    优点
    由MQ按异步的方式协调完成事务,性能较高。
    不用实现try/confirm/cancel接口,开发成本比TCC低。
    缺点
    此方式基于关系数据库本地事务来实现,会出现频繁读写数据库记录,浪费数据库资源,另外对于高并发操作不是最佳方案。

    展开全文
  • java实现分布式事务的三种方案

    千次阅读 2019-10-20 23:50:51
    如何实现两个分布式服务(订单服务、库存服务)共同完成一件事即订单支付成功自动自动减库存,这里 的关键是如何保证两个分布式服务的事务的一致性。 尝试解决上边的需求,在订单服务中远程调用减库存接口,伪代码...

    问题描述:

    用户支付完成会将支付状态及订单状态保存在订单数据库中,由订单服务去维护订单数据库。由库存服务去维护库存数据库的信息。下图是系统结构图:

    如何实现两个分布式服务(订单服务、库存服务)共同完成一件事即订单支付成功自动减库存,这里的关键是如何保证两个分布式服务的事务的一致性。
    尝试解决上边的需求,在订单服务中远程调用减库存接口,伪代码如下:

    订单支付结果通知方法{

    ​ 更新支付表中支付状态为“成功”。
    ​ 远程调用减库存接口减库存。

    上边的逻辑说明:
    1、更新支付表状态为本地数据库操作。
    2、远程调用减库存接口为网络远程调用请求。
    3、为保存事务上边两步操作由spring控制事务,当遇到Exception异常则回滚本地数据库操作。
    问题如下:
    1、如果更新支付表失败则抛出异常,不再执行远程调用,此设想没有问题。
    2、如果更新支付表成功,网络远程调用超时会拉长本地数据库事务时间,影响数据库性能。
    3、如果更新支付表成功,远程调用减库存成功(减库存数据库commit成功),最后更新支付表commit失败,此时出现操作不一致。
    上边的问题涉及到分布式事务控制。

    什么是分布式事务

    什么是分布式系统:

    部署在不同结点上的系统通过网络交互来完成协同工作的系统。
    比如:充值加积分的业务,用户在充值系统向自己的账户充钱,在积分系统中自己积分相应的增加。充值系统和积分系统是两个不同的系统,一次充值加积分的业务就需要这两个系统协同工作来完成。

    什么是事务:

    事务是指由一组操作组成的一个工作单元,这个工作单元具有原子性(atomicity)、一致性(consistency)、隔
    离性(isolation)和持久性(durability)。
    原子性:执行单元中的操作要么全部执行成功,要么全部失败。如果有一部分成功一部分失败那么成功的操作要全
    部回滚到执行前的状态。

    一致性:执行一次事务会使用数据从一个正确的状态转换到另一个正确的状态,执行前后数据都是完整的。

    隔离性:在该事务执行的过程中,任何数据的改变只存在于该事务之中,对外界没有影响,事务与事务之间是完全的隔离的。只有事务提交后其它事务才可以查询到最新的数据。

    持久性:事务完成后对数据的改变会永久性的存储起来,即使发生断电宕机数据依然在。

    什么是本地事务:

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

    什么是分布式事务:

    在分布式系统中一次操作由多个系统协同完成,这种一次事务操作涉及多个系统通过网络协同完成的过程称为分布
    式事务。这里强调的是多个系统通过网络协同完成一个事务的过程,并不强调多个系统访问了不同的数据库,即使
    多个系统访问的是同一个数据库也是分布式事务,如下图:

    另外一种分布式事务的表现是,一个应用程序使用了多个数据源连接了不同的数据库,当一次事务需要操作多个数
    据源,此时也属于分布式事务,当系统作了数据库拆分后会出现此种情况。

    分布式事务有哪些应用场景:

    1. 电商系统中的下单扣库存
      电商系统中,订单系统和库存系统是两个系统,一次下单的操作由两个系统协同完成
      2)金融系统中的银行卡充值
      在金融系统中通过银行卡向平台充值需要通过银行系统和金融系统协同完成。
      3)教育系统中下单选课业务
      在线教育系统中,用户购买课程,下单支付成功后学生选课成功,此事务由订单系统和选课系统协同完成。
      4) SNS系统的消息发送
      在社交系统中发送站内消息同时发送手机短信,一次消息发送由站内消息系统和手机通信系统协同完成。

    如何进行分布式事务控制

    CAP理论

    CAP理论是分布式事务处理的理论基础:分布式系统在设计时只能在一致性(Consistency)、可用性(Availability)、分区容忍性(PartitionTolerance)中满足两种,无法兼顾三种。

    一致性(Consistency):服务A、B、C三个结点都存储了用户数据, 三个结点的数据需要保持同一时刻数据一致性。
    可用性(Availability):服务A、B、C三个结点,其中一个结点宕机不影响整个集群对外提供服务,如果只有服务A结点,当服务A宕机整个系统将无法提供服务,增加服务B、C是为了保证系统的可用性。
    分区容忍性(Partition Tolerance):分区容忍性就是允许系统通过网络协同工作,分区容忍性要解决由于网络分区导致数据的不完整及无法访问等问题。

    分布式系统不可避免的出现了多个系统通过网络协同工作的场景,结点之间难免会出现网络中断、网延延迟等现
    象,这种现象一旦出现就导致数据被分散在不同的结点上,这就是网络分区

    分布式系统如果兼顾CAP:

    在保证分区容忍性的前提下一致性和可用性无法兼顾,如果要提高系统的可用性就要增加多个结点,如果要保证数据的一致性就要实现每个结点的数据一致,结点越多可用性越好,但是数据一致性越差。
    所以,在进行分布式系统设计时,同时满足“一致性”、“可用性”和“分区容忍性”三者是几乎不可能的。
    CAP有哪些组合方式?

    1. CA:放弃分区容忍性,加强一致性和可用性,关系数据库按照CA进行设计。
    2. AP:放弃一致性,加强可用性和分区容忍性,追求最终一致性,很多NoSQL数据库按照AP进行设计。
      说明:这里放弃一致性是指放弃强一致性,强一致性就是写入成功立刻要查询出最新数据。追求最终一致性是指允许暂时的数据不一致,只要最终在用户接受的时间内数据 一致即可。
    3. CP:放弃可用性,加强一致性和分区容忍性,一些强一致性要求的系统按CP进行设计,比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。说明:由于网络问题的存在CP系统可能会出现待等待超时,如果没有处理超时问题则整理系统会出现阻塞。

    总结

    ​ 在分布式系统设计中AP的应用较多,即保证分区容忍性和可用性,牺牲数据的强一致性(写操作后立刻读取到最新数据),保证数据最终一致性。比如:订单退款,今日退款成功,明日账户到账,只要在预定的用户可以接受的时间内退款事务走完即可。

    分布式事务一致性解决方案

    两阶段提交协议(2PC)

    ​ 为解决分布式系统的数据一致性问题出现了两阶段提交协议(2 Phase Commitment Protocol),两阶段提交由协调者和参与者组成,共经过两个阶段和三个操作,部分关系数据库如Oracle、MySQL支持两阶段提交协议,本节讲解关系数据库两阶段提交协议。

    参考:
    2PC:https://en.wikipedia.org/wiki/Two-phase_commit_protocol

    2PC协议流程图

    1)第一阶段:准备阶段(prepare)
    协调者通知参与者准备提交订单,参与者开始投票。
    参与者完成准备工作向协调者回应Yes|NO。
    2)第二阶段:提交(commit)/回滚(rollback)阶段
    协调者根据参与者的投票结果发起最终的提交指令。
    如果有参与者没有准备好则发起回滚指令。

    一个下单减库存的例子:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gg22D205-1571586550916)(https://i.loli.net/2019/10/20/4l8sradhvi1BuqG.png)]

    1、应用程序连接两个数据源。
    2、应用程序通过事务协调器向两个库发起prepare,两个数据库收到消息分别执行本地事务(记录日志),但不提交,如果执行成功则回复yes,否则回复no。
    3、事务协调器收到回复,只要有一方回复no则分别向参与者发起回滚事务,参与者开始回滚事务。
    4、事务协调器收到回复,全部回复yes,此时向参与者发起提交事务。如果参与者有一方提交事务失败则由事务协调器发起回滚事务。

    2PC的优点:实现强一致性,部分关系数据库支持(Oracle、MySQL等)。
    缺点:整个事务的执行需要由协调者在多个节点之间去协调,增加了事务的执行时间,性能低下。
    解决方案有:springboot+Atomikos or Bitronix
    3PC主要是解决协调者与参与者通信阻塞问题而产生的,它比2PC传递的消息还要多,性能不高。详细参考3PC:
    https://en.wikipedia.org/wiki/Three-phase_commit_protocol

    事务补偿 TCC

    TCC事务补偿是基于2PC实现的业务层事务控制方案,它是Try、Confirm和Cancel三个单词的首字母,含义如下:
    1、Try 检查及预留业务资源完成提交事务前的检查,并预留好资源。
    2、Confirm确定执行业务操作对try阶段预留的资源正式执行。
    3、Cancel取消执行业务操作对try阶段预留的资源释放。

    下边用一个下单减库存的业务为例来说明:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WV6xbtry-1571586550917)(https://i.loli.net/2019/10/20/qndSjc5VOaKMAh8.png)]

    1、Try
    下单业务由订单服务和库存服务协同完成,在try阶段订单服务和库存服务完成检查和预留资源。
    订单服务检查当前是否满足提交订单的条件(比如:当前存在未完成订单的不允许提交新订单)。
    库存服务检查当前是否有充足的库存,并锁定资源。
    2、Confirm
    订单服务和库存服务成功完成Try后开始正式执行资源操作。
    订单服务向订单写一条订单信息。
    库存服务减去库存。
    3、Cancel
    如果订单服务和库存服务有一方出现失败则全部取消操作。
    订单服务需要删除新增的订单信息。
    库存服务将减去的库存再还原。
    优点:最终保证数据的一致性,在业务层实现事务控制,灵活性好。
    缺点:开发成本高,每个事务操作每个参与者都需要实现try/confirm/cancel三个接口。

    注意:TCC的try/confirm/cancel接口都要实现幂等性,在为在try、confirm、cancel失败后要不断重试。

    什么是幂等性?
    幂等性是指同一个操作无论请求多少次,其结果都相同。
    幂等操作实现方式有:
    1、操作之前在业务方法进行判断如果执行过了就不再执行。
    2、缓存所有请求和处理的结果,已经处理的请求则直接返回结果。
    3、在数据库表中加一个状态字段(未处理,已处理),数据操作时判断未处理时再处理。

    消息队列实现最终一致性

    本方案是将分布式事务拆分成多个本地事务来完成,并且由消息队列异步协调完成,如下图:
    下边以下单减少库存为例来说明:

    可以把MQ去掉不使用MQ

    1、订单服务和库存服务完成检查和预留资源。
    2、订单服务在本地事务中完成添加订单表记录和添加“减少库存任务消息”。
    3、由定时任务根据消息表的记录发送给MQ通知库存服务执行减库存操作。
    4、库存服务执行减少库存,并且记录执行消息状态(为避免重复执行消息,在执行减库存之前查询是否执行过此消息)。
    5、库存服务向MQ发送完成减少库存的消息。
    6、订单服务接收到完成库存减少的消息后删除原来添加的“减少库存任务消息”。
    实现最终事务一致要求:预留资源成功理论上要求正式执行成功,如果执行失败会进行重试,要求业务执行方法实现幂等。

    优点 :
    由MQ按异步的方式协调完成事务,性能较高。
    不用实现try/confirm/cancel接口,开发成本比TCC低。
    缺点:
    此方式基于关系数据库本地事务来实现,会出现频繁读写数据库记录,浪费数据库资源,另外对于高并发操作不是最佳方案。

    浅谈分布式事务

    展开全文
  • 高级JAVA开发 分布式事务部分

    千次阅读 2020-07-04 18:03:51
    高级JAVA开发 分布式事务部分『分布式事务』中的相关概念2PC(Two Phase Commitment Protocol)XATCC3PC 参考和摘自: 分布式事务的4种模式 『分布式事务』中的相关概念 2PC(Two Phase Commitment Protocol) 2PC是...

    参考和摘自:
    分布式事务的4种模式

    本地事务

    ACID原则

    A:原子性(Atomicity):
    	一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
    	事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
    
    C:一致性(Consistency):
    	事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。
    		如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。
    		如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
    
    I:隔离性(Isolation):
    	指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
    	由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。
    	事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
    
    D:持久性(Durability):
    	指的是只要事务成功结束,它对数据库所做的更新就必须保存下来。
    

    隔离性:Mysql的4个事务隔离级别

    1、读未提交(Read Uncommited)(可能产生脏读,幻读,不可重复读):
    	该隔离级别允许脏读取,其隔离级别最低;
    	比如:
    		事务A和事务B同时进行,事务A在整个执行阶段,会将某数据的值从1开始一直加到10,然后进行事务提交,
    		此时,事务B能够看到这个数据项在事务A操作过程中的所有中间值(如1变成2,2变成3等)
    
    2、读已提交(Read Commited)(可能产生不可重复读,幻读):
    	读已提交只允许获取已经提交的数据。
    	比如:
    		事务A和事务B同时进行,事务A进行+1操作。
    		此时,事务B无法看到这个数据项在事务A操作过程中的所有中间值,只能看到最终的10。
    		但是事务B可能出现第一读取到1,第二次读取到事务A提交的数据10,造成不可重复读。
    	不可重复读指的是:同事务内,同一条数据两次读取到不同值的情况。
    	幻读指的是:同事务内,同一查询条件两次读取到不同条数的情况。
    
    3、可重复读(Repeatable Read)(可能产生幻读):
    	就是保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻是一致的,
    	因此该事务级别禁止不可重复读取和脏读取,但是有可能出现幻影数据。
    
    4、串行化:
    	是最严格的事务隔离级别,它要求所有事务被串行执行,即事务只能一个接一个的进行处理,不能并发执行。
    

    Mysql InnoDB引擎 RR隔离级别下产生幻读例子

    数据准备:
    	DROP TABLE IF EXISTS `test`;
    	CREATE TABLE `test` (
    	  `id` int(1) NOT NULL AUTO_INCREMENT,
    	  `name` varchar(8) DEFAULT NULL,
    	  PRIMARY KEY (`id`)
    	) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
    	BEGIN;
    		INSERT INTO `test` VALUES
    			 ('0', '小罗'), ('5', '小黄'), ('10', '小明'), ('15', '小红'), ('20', '小紫'), ('25', '小黑');
    	COMMIT;
    
    操作例子:
    ---- | -------------------------------------------------- | -----------------------------------------------------
    Time |                   Session1 TX1                     |             Session2 TX2 
    ---- | -------------------------------------------------- | -----------------------------------------------------
         | BEGIN;                                             |
      t1 | -- return row num 0	                              |
    	 | SELECT * FROM `test` WHERE `id`> 10 AND `id` < 15; |
    ---- | -------------------------------------------------- | -----------------------------------------------------
    	 |                                                    | BEGIN;
      t2 |                                                    | INSERT INTO `test` (`id`, `name`) VALUES (12, '李西');
    	 |                                                    | COMMIT;
    ---- | -------------------------------------------------- | -----------------------------------------------------
         | -- return row num 0	未幻读                         | 
         | SELECT * FROM `test` WHERE `id`> 10 AND `id` < 15; |   
    	 |                                                    | 
         | --  update TX2 提交的数据                            | 
      t3 | update `test` set `name` = 'aaa' where id = 12 ;   |
     	 |                                                    | 
         | -- return row num 1	产生幻读                       | 
         | SELECT * FROM `test` WHERE `id`> 10 AND `id` < 15; |
         | COMMIT;                                            |
    ---- | -------------------------------------------------- | -----------------------------------------------------
    
    Tips:
    	Mysql RR级别下有MVCC机制,解决了部分幻读问题(第二次读取)。
    	TX1的更新操作是多步的:读取id为12的数据行,更新数据,写入数据行。
    	更新操作读取时的操作是『当前读』,也就是读取到了TX2提交的最新数据,在此基础上做更新操作。
    	TX1第三次读取时,可以读取到本事务做的更新操作,这时也就产生了幻读。
    
    	如果TX1在第一次读取时改成这样:
    		SELECT * FROM `test` WHERE `id`> 10 AND `id` < 15 FOR UPDATE;
    	TX2在INSERT操作时会阻塞住,直到TX1 COMMIT,此时TX1 select 就不会产生幻读问题。
    

    分布式事务

    分布式系统中的理论

    CAP 原则(布鲁尔定理)

    在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

    一致性(C):
    	在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
    
    可用性(A):
    	在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
    
    分区容错性(P):
    	分区容错性是指系统能够容忍节点之间的网络通信的故障。
    	以实际效果而言,分区相当于对通信的时限要求。
    	系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
    

    CAP 在分布式系统中的权衡:

    CA:
    	在分布式系统中,如果要求所有节点数据的一致性(C)又要求所有节点的可用性(A),
    	那么在发生分区现象时(分区无法避免,因为存在多个节点)为了保证一致性(C),
    	分布式系统整体只能拒绝所有请求停止服务,等待节点分区问题解决后再继续提供服务。
    	此时已经违背了可用性(A)。
    	所以分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。
    
    CP:
    	放弃可用性(A),追求一致性和分区容忍性。在产生分区问题时,放弃可用性。ZooKeeper 其实就是追求的强一致。
    
    AP:
    	放弃一致性(C)(这里说的一致性是强一致性) 追求分区容错性和可用性,这是很多分布式系统设计时的选择,比如 Eueaka。
    

    CAP 理论中是忽略网络延迟的,也就是当事务提交时,从节点 A 到节点 B 没有延迟,但是在现实中这个是明显不可能的,所以总会有一定的时间是不一致。

    BASE 理论

    什么是BASE理论

    是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。
    是对 CAP 中 AP 的一个扩展,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

    基本可用:
    	分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
    
    软状态:
    	允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是 CAP 中的不一致。
    
    最终一致:
    	最终一致是指经过一段时间后,所有节点数据都将会达到一致。
    

    BASE 解决了 CAP 理论中没有网络延迟的情况,在 BASE 中用软状态和最终一致,保证了延迟后的一致性。
    BASE 和 ACID 是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。

    分布式事务中的理论

    XA规范

    X/Open组织 定义的一套DTP分布式事务的模型和规范。
    XA DTP分布式事务模型中的四个角色:

    AP(Application Program,应用程序)
    TM(Transaction Manager,事务管理器)
    RM(Resource Manager,资源管理器)通常指数据库
    CRM(Communication Resource Manager,通信资源管理器)
    

    XA是DTP模型定义TM和RM之前通讯的接口规范。XA接口函数由数据库厂商提供。TM中间件用它来通知数据库事务的开始、结束以及提交、回滚等。

    2PC(tow phase commit) 两阶段提交

    根据XA思想衍生出来的一致性协议。

    参与2PC的角色:

    协调者(coordinator)
    参与者(participants, 或cohort)
    

    保证事务在提交时,协调者和参与者处于一致性状态,如果其中有一个参与者出现了故障或者网络问题,不能及时的回应协调者,那么这次事务就宣告失败或者出现阻塞。

    两阶段:

    1、准备阶段:
    	事务协调者(事务管理器 TM)给每个参与者(资源管理器 RM)发送Prepare消息,
    	每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的redo和undo日志,但不提交
    	
    2、提交阶段
    	如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;
    	否则,发送提交(Commit)消息;
    	参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。
    	(注意:必须在最后阶段释放锁资源)
    

    2PC的缺点:
    二阶段提交看起来确实能够提供原子性的操作,但是不幸的是,二阶段提交还是有几个缺点的:

    1、同步阻塞问题。
    	在事务执行过程中,所有参与节点都是事务阻塞型的。
    	参与者占有公共资源时,其他第三方节点访问公共资源则会处于阻塞。
    
    2、单点故障。
    	在2PC中由协调者进行协调,一旦协调者发生故障,参与者会阻塞。
    	尤其在第二阶段commit阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。
    	注:如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题
    
    3、数据不一致。
    	在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常;
    	或者在发送commit请求过程中协调者发生了故障,导致只有一部分参与者接受到了commit请求。
    	而在这部分参与者接到commit请求之后就会执行commit操作。
    	但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。
    
    4、二阶段无法解决的问题:
    	协调者发出commit消息,并且只有部分参与者收到消息,此时协调者和收到消息的参与者发生宕机。
    	那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,集群中不能判断出事务是否被已经提交。
    

    TCC(Try-Confirm-Cancel)补偿事务

    TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:

    Try 阶段:
    	主要是对业务系统做检测及资源预留。
    
    Confirm 阶段:
    	主要是对业务系统做确认提交。
    	Try 阶段执行成功并开始执行 Confirm 阶段时,默认 Confirm 阶段是不会出错的。
    	即:只要 Try 成功,Confirm 一定成功。
    
    Cancel 阶段:
    	主要是在业务执行错误需要回滚的状态下执行的业务取消,预留资源释放。
    

    举个栗子:

    分布式系统中一个订单支付后会协调以下服务共同完成一系列操作:
    	订单服务 - 修改订单状态为已支付
    	库存服务 - 库存扣减
    	积分服务 - 给用户增加积分
    	仓储服务 - 创建销售出库单
    如果其中一个环节操作失败,那么其余服务应该回滚到订单支付前的状态。
    
    如果应用TCC解决方案,那么各个服务需要提供以下支持:
    	订单服务 
    		- 提供修改订单状态为 UPDATING 的接口		(Try)
    		- 提供修改订单状态为 PAYED 的接口			(Confirm)
    		- 提供修改订单状态为 UNPAID 的接口			(Cancel)
    	库存服务 
    		- 提供 冻结库存 接口						(Try)
    		- 提供 冻结库存提交 接口					(Confirm)
    		- 提供 冻结库存回滚 接口					(Cancel)
    	积分服务 
    		- 提供 增加积分 状态为 INEFFECTIVE 接口		(Try)
    		- 提供 修改积分状态为 EFFECTIVE 接口		(Confirm)
    		- 提供 删除积分记录 接口					(Cancel)
    	仓储服务
    		- 提供 创建出库单 状态为 INEFFECTIVE 接口	(Try)		
    		- 提供 修改出库单状态为 EFFECTIVE 接口		(Confirm)	
    		- 提供 删除出库单 接口						(Cancel)
    
    第一阶段:执行所有 Try 接口 预留资源
    第二阶段:如果有服务 Try 阶段预留资源失败,那么执行 Try 成功服务的 Cancel 接口,反之执行所有 Confirm 接口。
    

    TCC 事务框架要记录一些分布式事务的活动日志,保存分布式事务运行的各个阶段和状态。
    比如发现某个服务的 Cancel 或者 Confirm 一直没成功,会不停的重试调用它的 Cancel 或者 Confirm 逻辑,务必要它成功!

    优势与劣势:

    优势:
    	- TCC 分布式事务的实现方式的在于,可以让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。
    	
    缺点:
    	- 对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作。
    	- 现难度较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。
    	  为了满足一致性的要求,confirm和cancel接口还必须实现幂等。
    

    2PC 和 TCC 的异同点:

    从模式上来将,TCC类似2PC。抽象成逻辑即:
    	- 第一步试着操作数据,第二步则是在第一步基础上做确认动作或取消动作。
    
    但两者从根本上来说是截然不同的:
    	- 2PC更看重的是事务处理阶段、RM提供底层支持(一般是兼容XA)、Prepare、Commit和Rollback。
    	  一个完整的事务生命周期是:begin -> 业务逻辑 -> 逐个RM Prepare -> Commit/Rollback。
    	- TCC则更看重在业务层面的分步处理。													
    	  一个完整的事务生命周期是:begin -> 业务逻辑(逐个try业务) -> Comfirm业务/Cancel业务。
    

    3PC(tow phase commit) 三阶段提交

    在两阶段提交的基础上增加了CanCommit阶段,并引入了超时机制。
    一旦事务参与者迟迟没有收到协调者的Commit请求,就会自动进行本地commit,
    这样相对有效地解决了协调者单点故障的问题。
    但是性能问题和不一致问题仍然没有根本解决。

    CanCommit阶段:
    	事务的协调者向所有参与者询问“你们是否可以完成本次事务?”,
    	如果参与者节点认为自身可以完成事务就返回“YES”,否则“NO”。
    	而在实际的场景中参与者节点会对自身逻辑进行事务尝试,
    	其实说白了就是检查下自身状态的健康性,看有没有能力进行事务操作。
    
    PreCommit阶段:
    	在阶段一中,如果所有的参与者都返回Yes的话,那么就会进入PreCommit阶段进行事务预提交。
    	此时分布式事务协调者会向所有的参与者节点发送PreCommit请求。
    	参与者收到后开始执行事务操作,并将Undo和Redo信息记录到事务日志中。
    	参与者执行完事务操作后(此时属于未提交事务的状态),就会向协调者反馈“Ack”表示我已经准备好提交了,并等待协调者的下一步指令。
    	
    	否则,如果阶段一中有任何一个参与者节点返回的结果是No响应,
    	或者协调者在等待参与者节点反馈的过程中超时(2PC中只有协调者可以超时,参与者没有超时机制),
    	整个分布式事务就会中断,协调者就会向所有的参与者发送“abort”请求。
    
    DoCommit阶段:
    	在阶段二中如果所有的参与者节点都可以进行PreCommit提交,那么协调者就会从“预提交状态”->“提交状态”。
    	然后向所有的参与者节点发送"doCommit"请求。
    	参与者节点在收到提交请求后就会各自执行事务提交操作,
    	并向协调者节点反馈“Ack”消息,协调者收到所有参与者的Ack消息后完成事务。
    	
    	相反,如果有一个参与者节点未完成PreCommit的反馈或者反馈超时,
    	那么协调者都会向所有的参与者节点发送abort请求,从而中断事务。
    

    相比较2PC而言,3PC对于协调者(Coordinator)和参与者(Partcipant)都设置了超时时间,而2PC只有协调者才拥有超时机制。
    这个优化点主要是避免了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题。因为参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。
    另外,通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较于2PC而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。

    3PC依然没有完全解决数据不一致的问题。

    分布式事务的实现方案

    基于 JTA 实现的分布式事务

    何为 JTA:

    Java Transaction API,分布式事务的编程 API,基于 XA DTP 模型和规范。
    在J2EE中,单库的事务是通过JDBC事务来支持的,如果是跨多个库的事务,是通过 JTA API 来支持的。
    通过 JTA API 可以协调和管理横跨多个数据库的分布式事务。
    狭义的说,JTA 只是一套接口。
    

    开源的实现 JTA TM 的提供商:

    Java Open Transaction Manager (JOTM)
    JBoss TS
    Bitronix Transaction Manager (BTM)
    Atomikos
    Narayana
    

    JTA RM的提供商(XA接口):

    一般数据库都会提供实现,比如 Mysql、Oracle
    

    Mysql XA 事务支持官方文档:
    Mysql XA Documentation
    目前Mysql的XA模式仅限定在InnoDB引擎下。

    处理流程:

    - 事务管理器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交。
    - 事务协调器要求每个数据库提交数据,或者回滚数据。
    

    优缺点:

    优点:
    	尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于 MySQL 是从 5.5 开始支持。
    
    缺点(同2PC缺点):
    	同步阻塞:
    		在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
    	
    	单点问题:
    		事务管理器在整个流程中扮演的角色很关键,如果其宕机。
    		比如:
    			在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,
    			资源管理器就会一直阻塞,导致数据库无法使用。
    	
    	数据不一致:
    		两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能。
    		比如:
    			在第二阶段中,假设协调者发出了事务 Commit 的通知,
    			但是因为网络问题该通知仅被一部分参与者所收到并执行了 Commit 操作,
    			其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
    
    总的来说,XA 协议比较简单,成本较低,但是其单点问题,以及不能支持高并发(由于同步阻塞)依然是其最致命的弱点。
    

    实现栗子移步文章:https://blog.csdn.net/zhouhao88410234/article/details/91872872

    Seata 提供的分布式事务解决方案

    转载和参考自:
    http://seata.io/zh-cn/docs/overview/what-is-seata.html
    https://juejin.im/post/5d54effe6fb9a06aeb10b646
    https://www.jianshu.com/p/0ed828c2019a

    Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

    Seata 中有三大模块,分别是 TM(Transaction Manager)、RM(Resource Manager) 和 TC(Transaction Coordinator):

    TC - 事务协调者
    维护全局和分支事务的状态,驱动全局事务提交或回滚。
    
    TM - 事务管理器
    定义全局事务的范围:开始全局事务、提交或回滚全局事务。
    
    RM - 资源管理器
    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
    

    其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。

    在 Seata 中,分布式事务的执行流程:

    1. TM 开启分布式事务(TM 向 TC 注册全局事务记录);
    
    2. 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态);
     
    3. TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务);
     
    4. TC 汇总事务信息,决定分布式事务是提交还是回滚;
     
    5. TC 通知所有 RM 提交/回滚 资源,事务二阶段结束;
    

    事务模型

    在这里插入图片描述

    • TM 定义全局事务的边界。
    • RM 负责定义分支事务的边界和行为。
    • TC 跟 TM 和 RM 交互(开启、提交、回滚全局事务;分支注册、状态上报和分支的提交、回滚),做全局的协调。

    AT (Automatic Transaction)模式

    AT 模式 的前提:
    基于支持本地 ACID 事务的关系型数据库。
    Java 应用,通过 JDBC 访问数据库。
    
    整体机制

    整体分为两阶段:执行阶段、完成阶段。是两阶段提交协议的演变:

    一阶段(执行阶段):
    	业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
    二阶段(完成阶段):
    	提交异步化,非常快速地完成。
    	回滚通过一阶段的回滚日志进行反向补偿。
    

    一阶段(执行阶段)
    在这里插入图片描述
    Seata 的 JDBC 数据源代理通过对业务 SQL 的解析,把业务数据在更新前后的数据镜像组织成回滚日志,利用 本地事务 的 ACID 特性,将业务数据的更新和回滚日志的写入在同一个 本地事务 中提交。
    这样,可以保证:任何提交的业务数据的更新一定有相应的回滚日志存在。
    基于这样的机制,分支的本地事务便可以在全局事务的 执行阶段 提交,马上释放本地事务锁定的资源。

    二阶段(完成阶段)

    • 如果决议是全局提交,此时分支事务此时已经完成提交,不需要同步协调处理(只需要异步清理回滚日志),完成阶段 可以非常快速地结束。
      在这里插入图片描述

    • 如果决议是全局回滚,RM 收到协调器发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚。
      在这里插入图片描述

    隔离性
    写隔离
    一阶段本地事务提交前,需要确保先拿到 全局锁 。
    拿不到 全局锁 ,不能提交本地事务。
    拿 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。
    

    以一个示例来说明:

    两个全局事务 tx1 和 tx2,分别对 a 表的 m 字段进行更新操作,m 的初始值 1000。

    tx1 先开始,开启本地事务,拿到本地锁,更新操作 m = 1000 - 100 = 900。本地事务提交前,先拿到该记录的 全局锁 ,本地提交释放本地锁。 tx2 后开始,开启本地事务,拿到本地锁,更新操作 m = 900 - 100 = 800。本地事务提交前,尝试拿该记录的 全局锁 ,tx1 全局提交前,该记录的全局锁被 tx1 持有,tx2 需要重试等待 全局锁 。

    在这里插入图片描述
    tx1 二阶段全局提交,释放 全局锁 。tx2 拿到 全局锁 提交本地事务。

    在这里插入图片描述
    如果 tx1 的二阶段全局回滚,则 tx1 需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

    此时,如果 tx2 仍在等待该数据的 全局锁,同时持有本地锁,则 tx1 的分支回滚会失败。分支的回滚会一直重试,直到 tx2 的 全局锁 等锁超时,放弃 全局锁 并回滚本地事务释放本地锁,tx1 的分支回滚最终成功。

    因为整个过程 全局锁 在 tx1 结束前一直是被 tx1 持有的,所以不会发生 脏写 的问题。

    读隔离

    在数据库本地事务隔离级别 读已提交(Read Committed) 或以上的基础上,Seata(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted) 。

    如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

    在这里插入图片描述
    SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。

    出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。

    全局锁是由 TC 也就是 server 来集中维护,而不是在数据库维护的。这样做有两点好处:

    一方面:锁的释放非常快
    	  尤其是在全局提交的情况下,收到全局提交的请求,锁马上就释放掉了,不需要与 RM 或数据库进行一轮交互。
    另外一方面:因为锁不是数据库维护的,从数据库层面看,数据没有锁定。
          这也就是给极端情况下,业务 降级 提供了方便,事务协调器异常导致的一部分异常事务,不会 block 后面业务的继续进行。
    

    TCC 模式

    TCC模式需要对业务模型进行拆分,把原一次操作成功的业务拆分成两阶段实现。

    TCC设计举例

    以“扣钱”场景为例,在接入 TCC 前,对 A 账户的扣钱,只需一条更新账户余额的 SQL 便能完成;但是在接入 TCC 之后,用户就需要考虑如何将原来一步就能完成的扣钱操作,拆成两阶段,实现成三个方法,并且保证一阶段 Try 成功的话 二阶段 Confirm 一定能成功。

    在这里插入图片描述
    如上图所示,Try 方法作为一阶段准备方法,需要做资源的检查和预留。在扣钱场景下,Try 要做的事情是就是检查账户余额是否充足,预留转账资金,预留的方式就是冻结 A 账户的 转账资金。Try 方法执行之后,账号 A 余额虽然还是 100,但是其中 30 元已经被冻结了,不能被其他事务使用。
    二阶段 Confirm 方法执行真正的扣钱操作。Confirm 会使用 Try 阶段冻结的资金,执行账号扣款。Confirm 方法执行之后,账号 A 在一阶段中冻结的 30 元已经被扣除,账号 A 余额变成 70 元 。
    如果二阶段是回滚的话,就需要在 Cancel 方法内释放一阶段 Try 冻结的 30 元,使账号 A 的回到初始状态,100 元全部可用。
    用户接入 TCC 模式,最重要的事情就是考虑如何将业务模型拆成 2 阶段,实现成 TCC 的 3 个方法,并且保证 Try 成功 Confirm 一定能成功。相对于 AT 模式,TCC 模式对业务代码有一定的侵入性,但是 TCC 模式无 AT 模式的全局行锁,TCC 性能会比 AT 模式高很多。

    使用TCC模式需要注意的问题
    允许空回滚
    场景:
    	- Try 未执行,Cancel 执行了
    出现原因:
    	- Try 超时(丢包)
    	- 分布式事务回滚触发 Cancel
    	- 未收到 Try,收到 Cancel
    

    Cancel 接口设计时需要允许空回滚。

    在 Try 接口因为丢包时没有收到,事务管理器会触发回滚,这时会触发 Cancel 接口,这时 Cancel 执行时发现没有对应的事务 xid 或主键时,需要返回回滚成功。让事务服务管理器认为已回滚,否则会不断重试,而 Cancel 又没有对应的业务数据可以进行回滚。

    防悬挂控制
    场景:
    	- Cancel 比 Try 先执行
    出现原因:
    	- Try超时(拥堵)
    	- 分布式事务回滚触发 Cancel
    	- 拥堵的 Try 到达
    

    此时需要允许空回滚,但要拒绝空回滚后的Try操作

    悬挂的意思是:Cancel 比 Try 接口先执行,出现的原因是 Try 由于网络拥堵而超时,事务管理器生成回滚,触发 Cancel 接口,而最终又收到了 Try 接口调用,但是 Cancel 比 Try 先到。按照前面允许空回滚的逻辑,回滚会返回成功,事务管理器认为事务已回滚成功,则此时的 Try 接口不应该执行,否则会产生数据不一致,所以我们在 Cancel 空回滚返回成功之前先记录该条事务 xid 或业务主键,标识这条记录已经回滚过,Try 接口先检查这条事务xid或业务主键如果已经标记为回滚成功过,则不执行 Try 的业务操作。

    幂等控制

    Try、Confirm、Cancel 三个方法均需要保证幂等性。

    幂等性的意思是:对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。因为网络抖动或拥堵可能会超时,事务管理器会对资源进行重试操作,所以很可能一个业务操作会被重复调用,为了不因为重复调用而多次占用资源,需要对服务设计时进行幂等控制,通常我们可以用事务 xid 或业务主键判重来控制。

    Saga 模式

    http://seata.io/zh-cn/docs/user/saga.html

    XA 模式

    https://blog.csdn.net/weixin_47067712/article/details/106090353

    基于 MQ 实现的『最终一致性』分布式事务解决方案

    基于 MQ实现的『最终一致性』分布式事务解决方案 不适用强一致性的场景。
    比如 系统A是下单服务、系统B是仓储服务。在下单服务成功后,仓储服务消费到消息时点无法保证仓储数据是否满足要求。
    此种解决方案适用于对时延要求不高的场景。比如。系统A为下单服务、系统B为积分服务。下单成功后总会保证积分累加成功、但什么时候成功就不一定了。

    基于『本地消息表』和 MQ 实现的『最终一致性』分布式事务解决方案

    在这里插入图片描述
    执行步骤:

    1. 系统A执行本地业务,写入A系统消息表数据,生成唯一msgId,state设置为待处理,重复投递次数设置为0,此操作保证在一个事务里。
    2. 如果步骤1执行成功,尝试向MQ发送带msgId消息,通知系统B进行下一步处理。
    	此操作可能出现失败(MQ宕机、MQ网络超时等等),不过没关系,我们已经保存住了任务存根(A系统消息表数据)。
    3. 消费者接收数据。
    4. 处理消息,在写入DB时开启事务,保证业务处理操作和B系统消息表操作同时成功,并且消息表的msgId为唯一键,既能保证幂等,又能记录消费成功的消息。
    5. 定时任务系统C轮询查询A系统消息表 state 为待处理的消息 与 B系统消息表比对。
    	A、B同时存在的消息:
    		处理成功的消息,修改A表消息状态为已处理。
    	A存在、B不存在的消息:重复投递消息,增加A消息表重复投递次数,次数超过阈值报警。
    		可能B处理失败
    		可能A投递消息失败
    		可能B还没来得及处理积压在MQ中
    		可能B正在处理消息还没来得及提交事务
    

    基于『可靠消息队列(RocketMQ)』实现的『最终一致性』分布式事务解决方案

    在这里插入图片描述
    执行步骤:

    首先,MQ需要开启持久化,保证消息在MQ环节不丢失
    
    1. 注册回查监听
    		如果步骤4执行失败,MQ会定时发送通知询问是否需要提交或者回滚
    		在此监听中实现查询步骤3的业务状态返回给MQ
    2. 向MQ发送消息
    		消息处于Prepared状态,拿到msgId
    3. 步骤2执行成功后开启本地事务,执行本地业务
       步骤2执行失败则流程结束
    4. 步骤3执行成功向MQ发送Commit消息,表示可以向下游投递
       步骤3执行失败向MQ发送Rollback消息,取消投递
    		如果步骤4执行失败,则依靠步骤1中的回查机制来确认消息是否需要投递
    5. 消费者接收到消息投递
    		如果步骤6或者7失败,这里会收到重复投递的消息
    6. 消费者开启本地事务处理消息,并且保证消息的幂等性
    7. 手动ACK给MQ,确认消息消费成功
    
    展开全文
  • Java分布式事务

    万次阅读 2020-07-16 17:00:36
    分布式事务介绍 事务拥有以下四个特性,习惯上被称为ACID特性:

    分布式事务介绍

    1.1 什么是事务

    数据库事务(简称:事务,Transaction)是指数据库执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成[由当前业务逻辑多个不同操作构成]。

    事务拥有以下四个特性,习惯上被称为ACID特性:

    原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。记录之前的版本,允许回滚。

    一致性(Consistency):一致性是指事务使得系统从一个一致的状态转到另一个一致状态。事务的一致性决定了一个系统设计和实现的复杂度,也导致了事务的不同隔离级别。事务开始和结束之间的中间状态不会被其他事务看到。

    隔离性(Isolation):多个事务并发执行时,并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。适当的破坏一致性来提升性能与并行度

    持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。每一次的事务提交后就会保证不会丢失。

    延申拓展:

    事务隔离性(面试):

    • 脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
    • 幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A新增提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。
    • 不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A更新或删除提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这会导致锁竞争加剧,影响性能。

    事务的隔离级别(面试):

    • Read Uncommitted(读未提交):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
    • Read Committed(读已提交):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
    • Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
    • Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

    自行复习:spring事务的传播机制(spring事务面试必问)

     

    1.2 什么是分布式事务

    分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上,且属于不同的应用,分布式事务需要保证这些操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

    1.3 事务的演变

    1.3.1 单服务单数据库的本地事务

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

     

    1.3.2 单一服务多数据库的分布式事务

    最早的分布式事务应用架构很简单,不涉及服务间的访问调用,仅仅是服务内操作涉及到对多个数据库资源的访问。

     

    1.3.3 多服务多数据库的分布式事务

    当一个服务操作访问不同的数据库资源,又希望对它们的访问具有事务特性时,就需要采用分布式事务来协调所有的事务参与者。在这种情况下,起始于某个服务的事务在调用另外一个服务的时候,需要以某种机制流转到另外一个服务,从而使被调用的服务访问的资源也自动加入到该事务当中来。下图反映了这样一个跨越多个服务的分布式事务:

     

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

    如果将上面这两种场景(一个服务可以调用多个数据库资源,也可以调用其他服务)结合在一起,对此进行延伸,整个分布式事务的参与者将会组成如下图所示的树形拓扑结构。在一个跨服务的分布式事务中,事务的发起者和提交均系同一个,它可以是整个调用的客户端,也可以是客户端最先调用的那个服务。

     

    较之基于单一数据库资源访问的本地事务,分布式事务的应用架构更为复杂。在不同的分布式应用架构下,实现一个分布式事务要考虑的问题并不完全一样,比如对多资源的协调、事务的跨服务传播等,实现机制也是复杂多变。

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

    1.4 CAP定理(面试)

    CAP 定理,又被叫作布鲁尔定理。对于设计分布式系统(不仅仅是分布式事务)的架构师来说,CAP 就是你的入门理论。

     

    C (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。

    对于数据分布在不同节点上的数据来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。

    A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。

    合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回 50,而不是返回 40。

    P (网络分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。

     

    2 分布式事务解决方案(面试)

    1.XA两段提交(强一致)

    2.TCC三段提交(强一致)

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

    4.事务消息(RocketMQ[alibaba])(最终一致)

    5.Seata(alibaba)

    6.RabbitMQ的ACK机制实现分布式事务(拓展)

     

    一致性拓展:

    • 强一致性:读操作可以立即读到提交的更新操作。
    • 弱一致性:提交的更新操作,不一定立即会被读操作读到,读操作读到最新值需要一段时间。
    • 最终一致性:是弱一致性的特例。事务A更新一份数据后,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到事务A更新的最新值。如果没有错误发生,不一致时间的长短依赖于:通信延迟,系统负载等。

     

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

    X/Open 组织(即现在的 Open Group )定义了分布式事务处理模型

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

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

    一个事务协调者(coordinator):负责协调多个参与者进行事务投票及提交(回滚) 多个事务参与者(participants):即本地事务执行者

    总共处理步骤有两个 (1)投票阶段(voting phase):协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。参与者将告知协调者自己的决策:同意(事务参与者本地事务执行成功,但未提交)或取消(本地事务执行故障);

    (2)提交阶段(commit phase):收到参与者的通知后,协调者再向参与者发出通知,根据反馈情况决定各参与者是否要提交还是回滚;

     

     

    如果任一资源管理器在第一阶段返回准备失败,那么事务管理器会要求所有资源管理器在第二阶段执行回滚操作。通过事务管理器的两阶段协调,最终所有资源管理器要么全部提交,要么全部回滚,最终状态都是一致的

     

    优点: 尽量保证了数据的强一致(无法完全保证),适合对数据强一致要求很高的关键领域。

    缺点:

    • 同步阻塞问题:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
    • 单点故障:由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
    • 数据不一致:在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
    • 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交

     

    2.2 三段提交(3PC)

    三段提交是两段提交的升级版

    CanCommit阶段:询问阶段

     

     

    类似2PC的准备阶段,协调者向参与者发送CanCommit请求,询问是否可以执行事务提交操作,然后开始等待参与者的响应。

     

    PreCommit阶段:事务执行但不提交阶段

     

    协调者根据参与者的反应情况来决定是否可以进行事务的PreCommit操作:

    • 协调者从所有的参与者获得的反馈都是Yes响应

      1. 发送预提交请求协调者向参与者发送PreCommit请求;
      2. 参与者接收到PreCommit请求后,执行事务操作,并将undo(执行前数据)和redo(执行后数据)信息记录到事务日志中;
      3. 参与者成功的执行了事务操作,则返回ACK(确认机制:已确认执行)响应,同时开始等待最终指令。
    • 有任何一个参与者向协调者发送了No响应,或者等待超时

      1. 协调者向所有参与者发送中断请求请求。
    1. 参与者收到来自协调者的中断请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

     

    doCommit阶段:事务提交阶段

     

    • 执行提交

      1. 协调接收到所有参与者返回的ACK响应后,协调者向所有参与者发送doCommit请求。
      2. 参与者接收到doCommit请求之后,执行最终事务提交,事务提交完之后,向协调者发送Ack响应并释放所有事务资源。
      3. 协调者接收到所有参与者的ACK响应之后,完成事务。
    • 中断事务

      1. 协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),协调者向所有参与者发送中断请求;
      2. 参与者接收到中断请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后,向协调者发送ACK消息,释放所有的事务资源。
      3. 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。

       

    优点:相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。

    缺点:会导致数据一致性问题。由于网络原因,协调者发送的中断响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到中断命令并执行回滚的参与者之间存在数据不一致的情况。

     

    2.3 TCC补偿机制

    TTCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。三个阶段如下:

    操作方法含义
    Try预留业务资源/数据效验-尝试检查当前操作是否可执行
    Confirm确认执行业务操作,实际提交数据,不做任何业务检查。try成功,confirm必定成功
    Cancel执行业务出错时,需要回滚数据的状态下执行的业务逻辑

    其核心在于将业务分为两个操作步骤完成。不依赖事务协调器对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。

     

    例如: 小红要向小白转账100元,执行流程:

    1. 首先在 Try 阶段,要先调用远程接口检查小红的账户余额是否大于等于100元,若足够则对余额进行冻结,检查小白的账户状态是否正常。
    2. 在 Confirm 阶段,执行远程调用的转账的操作,扣除小红账户100元,小白账户加100元。
    3. 如果第2步执行成功,那么转账成功,小红账户解冻,流程结束。
    4. 如果第二步执行失败,则调用服务A的Cancel方法,账户余额回滚100元及解冻小红账户,同时调用服务B的Cancel方法,账户扣除100元。

    优点: 跟2PC比起来,实现以及流程相对简单了一些。

    缺点:

    • 在2 3 4步中都有可能失败,从而导致数据不一致。
    • TCC属于应用层的一种补偿方式,需要程序员在实现的时候多写很多补偿的代码,复杂业务场景下代码逻辑非常复杂。
    • 幂等性无法确保。

     

    2.4 本地消息表(异步确保)

    本地消息表这种实现方式应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理,这种思路是来源于ebay。我们可以从下面的流程图中看出其中的一些细节:

     

    工作流程:

    1. 消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。如果消息发送失败,会进行重试发送。
    2. 消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。
    3. 生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。

     

    优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。

    缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

     

    2.5 MQ 事务消息

    有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持(RabbitMQ、Kafka基于ACK机制)。

    以阿里的 RocketMQ 中间件为例,流程为:

    1. 发送一个事务消息,这个时候,RocketMQ将消息状态标记为Prepared,注意此时这条消息消费者是无法消费到的。
    2. 执行业务代码逻辑。
    3. 确认发送消息,RocketMQ将消息状态标记为可消费,这个时候消费者才能真正消费到这条消息。
    4. 如果步骤3确认消息发送失败,RocketMQ会定期扫描消息集群中的事务消息,如果发现了Prepared消息,它会向消息发送端(生产者)确认。RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。

    正常流程图:

     

    完整流程图:

     

    优点: 实现了最终一致性,不需要依赖本地数据库事务。

    缺点: 目前主流MQ中只有RocketMQ支持事务消息。

     

    延申拓展:

    MQ非事务消息实现:

    • 方案一:创建独立消息服务
    • 方案二:使用非事务MQ(RabbitMQ/Kafka)的ACK机制

     

    2.6 Seata

    2.6.1 Seata简介

    2019 年 1 月,阿里巴巴中间件团队发起了开源项目 Fescar(Fast & EaSy Commit And Rollback),和社区一起共建开源分布式事务解决方案。Fescar 的愿景是让分布式事务的使用像本地事务的使用一样,简单和高效,并逐步解决开发者们遇到的分布式事务方面的所有难题。

    Fescar 开源后,蚂蚁金服加入 Fescar 社区参与共建,并在 Fescar 0.4.0 版本中贡献了 TCC 模式。

    为了打造更中立、更开放、生态更加丰富的分布式事务开源社区,经过社区核心成员的投票,大家决定对 Fescar 进行品牌升级,并更名为 Seata,意为:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事务解决方案。

    Seata 融合了阿里巴巴和蚂蚁金服在分布式事务技术上的积累,并沉淀了新零售、云计算和新金融等场景下丰富的实践经验。

     

    核心组件:

    • Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
    • Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
    • Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

     

    工作流程:

    1. TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的事务ID(XID),XID 在微服务调用链路的上下文中传播。
    2. RM 向 TC 注册分支事务,接着执行这个分支事务并提交事务(重点:RM在此阶段就已经执行了本地事务的提交/回滚),最后将执行结果汇报给TC。
    3. TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。
    4. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

     

    2.6.2 Seata支持的模式

    seata中有两种常见分布式事务实现方案,AT及TCC

    • AT模式:赖于RM拥有本地数据库事务的能力,对于客户业务无侵入性

    • TCC 模式

       

    2.6.3 Seata的优点

    对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入 高性能:减少分布式事务解决方案所带来的性能消耗(2PC)

     

    2.6.4 AT模式

    Seata AT模式是基于XA事务演进而来的一个分布式事务中间件,XA是一个基于数据库实现的分布式事务协议,本质上和两阶段提交一样,需要数据库支持,Mysql5.6以上版本支持XA协议,其他数据库如Oracle,DB2也实现了XA接口。

    AT模式分为两个阶段,如下:

    • 第一阶段:本地数据备份阶段
    1. Seata 的 JDBC 数据源代理通过对业务 SQL 的解析,把业务数据在变化前后的数据镜像组织成回滚日志(XID/分支事务ID(Branch ID/变化前的数据/变化后的数据)。将回滚日志存入一张日志表UNDO_LOG(需要手动创建),并对UNDO_LOG表中的这条数据形成行锁(for update)。若锁定失败,说明有其他事务在操作这条数据,它会在一段时间内重试,重试失败则回滚本地事务,并向TC汇报本地事务执行失败。
    2. 将回滚日志存入一张日志表UNDO_LOG(需要手动创建),并对UNDO_LOG表中的这条数据形成行锁(for update)。
    3. 若锁定失败,说明有其他事务在操作这条数据,它会在一段时间内重试,重试失败则回滚本地事务,并向TC汇报本地事务执行失败。

    这样,可以保证:任何提交的业务数据的更新一定有相应的回滚日志存在

     

    目的:

    1. 基于这样的机制,分支的本地事务便可以在全局事务的第一阶段提交,并马上释放本地事务锁定的资源。
    2. 有了回滚日志之后,可以在第一阶段释放对资源的锁定,降低了锁范围,提高效率,即使第二阶段发生异常需要回滚,只需找对undolog中对应数据并反解析成sql来达到回滚目的。
    3. Seata通过代理数据源(DataSource->DataSourceProxy)将业务sql的执行解析成undolog来与业务数据的更新同时入库,达到了对业务无侵入的效果

     

    第二阶段:全局事务提交/回滚

    • 全局提交

      1. 所有分支事务此时已经完成提交,所有分支事务提交都正常。
      2. TM从TC获知后会决议执行全局提交,TC异步通知所有的RM释放UNDO_LOG表中的行锁,同时清理掉UNDO_LOG表中刚才释放锁的那条数据。

     

    • 全局回滚

      1. 若任何一个RM一阶段事务提交失败,通知TC提交失败。
      2. TM从TC获知后会决议执行全局回滚,TC向所有的RM发送回滚请求。
      3. RM通过XID和Branch ID找到相应的回滚日志记录,通过回滚记录生成反向的更新 SQL 并执行,以完成分支的回滚,同时释放锁,清除UNDO_LOG表中释放锁的那条数据。

     

    2.6.5 TCC模式

    seata也针对TCC做了适配兼容,支持TCC事务方案,原理前面已经介绍过,基本思路就是使用侵入业务上的补偿及事务管理器的协调来达到全局事务的一起提交及回滚。

     

    展开全文
  • 分布式事务基本理论 基本概念 通常把一个数据库内部的事务处理,如对多个表的操作,作为本地事务看待。数据库的事务处理对象是本地事务,而分布式事务处理的对象是全局事务。 所谓全局事务,是指分布式事务处理环境...
  • 该Demo实现的是一个Web项目下操作两个数据库,实现分布式事务
  • java分布式事务demo

    2020-04-06 22:40:06
    java分布式事务demo
  • Seata实现分布式事务

    万次阅读 多人点赞 2020-08-01 14:20:52
    Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。 Seata中的组件角色 TC(事务协调者...
  • Java微服务下的分布式事务介绍及其解决方案

    万次阅读 多人点赞 2019-03-22 15:48:46
    1.前言 ...这就很尴尬了,当然微服务下可能没有分布式事务,但是很多场景是需要分布式事务的,下面我就来介绍下什么是分布式事务,和分布式事务的解决方案 2 问题描述 在介绍分布式事务...
  • Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务... 掌握Seata实现分布式事务的原理  掌握Seata分布式事务框架的工作模式  掌握Seata在微服务中处理分布式问题实战 课程部分截图:
  • tomcat里面的a接口向mysql插入数据,weblogic里面的b接口向oracle删除数据,jetty里面的c接口向db2更新数据. ...现在a接口里面添加了2行代码,即调用b接口和c接口,当c接口更新失败的时候如何实现a接口与b接口的事务性回滚?
  • 参考:Java实现转账业务
  • kafka实现分布式事务解决方案

    千次阅读 2020-08-25 08:03:10
    分布式事务 ##概念: 分布式事务就是指事务的参与者、支持事务的服务器、资源服务器...实现分布式事务方案有很多种,有阿里的seata,基于tcc的高性能分布式事务框架hmily和lcn等开源框架外,还有基于mq来实现分布式事
  • Java分布式事务(JTA和XA)

    千次阅读 2019-06-13 16:45:25
    何为分布式事务 一个事务包含多个操作,多个操作操作了多个数据源,这样的事务称为分布式事务。 案例 为什么不能简单的借助数据源的本地事务 用数据源本地事务代码案例 Con1 = db1.getConn..; Con2 = db2.getConn.....
  • java实现分布式

    2020-02-19 22:16:19
    那什么是分布式锁呢,它又是用来解决哪些问题的呢? 在 JVM 中,在多线程并发的情况下,我们可以使用同步锁或 Lock 锁,保证在同一时间内...这时,我们就需要实现分布式锁来保证共享资源的原子性。除此之外,分布式...
  • java事务和分布式事务详解

    千次阅读 2018-11-06 23:18:14
    面试经常会问到分布式锁、分布式事务、SOA 服务化、分布式系统等业务、架构的问题和解决方案,工作中接触的业务方面事关金融,也需要解决一些类似的业务问题,所以总结了一篇浅谈分享,后面实战篇正在准备,这几周会...
  • mq实现分布式事务-补偿事务一致性CAP原则Rocket mq实现思路Rabbit mq实现思路需要考虑的问题后记 严格的来说,消息中间件并不能实现分布式事务,而是通过事后补偿机制,达到和分布式事务一样的数据一致性。这里主要...
  • TC作为微服务下的依赖,TM是独立的服务,主要作为事务管理的控制中心。 发起方发起会缓存事务的gtoupid到tx-manager中,根据最后的处理结果进行commit或者cancel操作。根据官网,tx-manager是支持集群服务的。 2....
  • java分布式事务

    千次阅读 2016-10-10 17:30:13
    在本系列先前的文章中,我们主要讲解了JDBC对本地事务的处理,本篇文章将讲到一个分布式事务的例子。    请通过以下方式下载github源代码: git clone ...
  • ZooKeeper 实现分布式事务,类似于两阶段提交,总共分为以下 4 步: 1. 客户端先给 ZooKeeper 节点发送写请求; 2. ZooKeeper 节点将写请求转发给 Leader 节点,Leader 广播给集群要去投票,等待确认; 3. Leader...
  •  JTA是J2EE的规范之一,如果使用JTA,我们需要去实现相应接口。...本文介绍如何使用tomcat+JTA实现多数据源的分布式事务。  一 选型   tomcat需要使用插件实现JTA,常用插件有jotm和atomikos,本文以atomi...
  • 简述分布式事务指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。解决方案在分布式系统中,要实现分布式事务,...
  • java分布式事务(JTA)实现 jotm和atomikos

    千次阅读 2015-02-09 14:22:28
    首先解释一个概念:本地事务和分布式事务。 本地事务:只处理单一数据源,比如单个数据库下,事务进行控制。... 在Java中,分布式事务主要的规范是JTA/XA。其中:JTA是Java的事务管理器规范, XA是工业标准的X/Open C
  • 一,什么是分布式事务分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作...
  • 使用消息中间件解决分布式事务的问题,是在分布式事务框架还没有真正流行起来的时候比较常用的解决此类问题的手段。使用消息中间件解决分布式事务问题,也有2种主要的思考方向,一种是通过消息表,另一种就是借助...
  • Java微服务系统分布式事务解决方案

    千次阅读 2019-07-12 11:58:11
    只要聊到做了分布式系统,必问分布式事务,若你对分布式事务一无所知的话,确实很坑,起码得知道有哪些方案,一般怎么来做,每个方案的优缺点是什么。 现在面试,分布式系统成了标配,而分布式系统带来的分布式事务...
  • RabbitMQ实现分布式事务方案: 1.生产者一定要把消息发送到MQ服务器中 生产者采用Confirm确认应答机制 如果发送到MQ服务器失败,采用重试机制 2.消费者能够正常消费MQ的消息 采用手动ack模式和重试机制,需要...
  • Java分布式事务概念与实现示例

    千次阅读 2005-05-26 15:13:00
    java中有如下三种事务,简单的JDBC级的事务 JTA - 在EJB...下面讨论如何在Java程序里实现分布式事务,即在同一个事务里访问多个数据源。实际上就是如何使用JTA. 这里假设使用Oracle数据库,使用WebLogic部署应用,

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 134,153
精华内容 53,661
关键字:

java实现分布式事务

java 订阅