精华内容
下载资源
问答
  • 一、分布式事物:本地事务和分布式事务(2PC+3PC)+传统分布式事务的问题 (一)本地事务和分布式事务(2PC+3PC) (1)两阶段提交协议2PC (2)三阶段提交协议3PC (二)对于微服务,传统分布式事务存在的问题 ...

    目录

    一、分布式事物:本地事务和分布式事务(2PC+3PC)+传统分布式事务的问题

    (一)本地事务和分布式事务(2PC+3PC)

    (1)两阶段提交协议2PC

    (2)三阶段提交协议3PC

    (二)对于微服务,传统分布式事务存在的问题

    二、CAP理论和BASE思想

    1.CAP理论

    一致性Consistency:

    可用性Availability:

    分区容错性PartitionTolerance:

    2.BASE思想

    BasicallyAvailiable(基本可用):

    SoftState(软状态):

    EventualConsistency(最终一致性):

    3.CAP理论和BASE思想的关联性

    三、可靠事件模式

    1.基本思路

    (1)用户下单

    (2)交易支付

    (3)订单更新

    2.关键点

    3.解决方案

    4.实现策略

    (1)事件确认组件

    (2)事件恢复组件

    (3)实时消息传递组件

    四、补偿模式

    1.基本思路

    2.关键点

    3.解决方案

    五、Sagas长事务模式--错误管理模式,同时用于控制复杂事务的执行和回滚

    1.基本思路

    2.解决方案

    六、TCC模式

    1.基本思路

    2.解决方案

    3.实现策略

    七、最大努力通知模式

    1.基本思路

    2.解决方案

    八、人工干预模式

    1.基本思路

    2.解决方案

    九、数据一致性模式总结

    参考书籍、文献和资料:


    一、分布式事物:本地事务和分布式事务(2PC+3PC)+传统分布式事务的问题

    (一)本地事务和分布式事务(2PC+3PC)

    传统单体应用一般都会使用一个关系型数据库,好处是使用ACID事务特性,保证数据一致性只需要开启一个事务,然后执行更新操作,最后提交事务或回滚事务。更方便的是可以以借助于Spring等数据访问技术和框架后只需要关注引起数据改变的业务本身即可。

    但是随着组织规模不断扩大、业务量不断增加,单块应用不足以支持庞大业务量和数据量,就需要对服务和数据进行拆分,拆分后就会出现两个或两个以上的数据库的情况,此时不能依靠本地事务得以解决,需要借助于分布式事务来保证一致性,常说的就是保持强一致性的两阶段提交协议和三阶段提交协议。

    (1)两阶段提交协议2PC

    准备阶段:由协调者提议并收集其他节点参与者的反馈(提议的节点为协调者,参与决议的节点为参与者)。

    执行阶段:根据反馈决定提交或中止事务。

    如图,协调者发起一个提议分别询问各参与者是否接受场景,然后协调者根据参与者的反馈,提交或中止事务。

    注意:只有当所有参与者都同意才提交,否则只有有一个不同意就中止。            

    但是,2PC有其固有的三大问题:

    问题一:同步阻塞问题

    执行过程中,所有参与者都是事务阻塞型的。当参与者占用公共资源时,其他第三方节点访问公共资源就不得不处于阻塞状态。

    问题二:单点故障

    一旦协调者发生故障,参与者会一直阻塞下去。特别是在第二阶段,协调者发生故障,则所有参与者还处于锁定资源的状态中,但是无法完成后续的事务操作。

    问题三:数据不一致

    当协调者向参与者发送提交请求后发生了局部网络异常,或者在发送提交请求过程中协调者发生了故障,就会导致只有一部分参与者接收到了提交请求,这部分参与者接到请求后就会执行提交操作,而未接收到提交请求的机器就无法执行事务提交,于是就出现了数据不一致的问题。

    (2)三阶段提交协议3PC

    与2PC相比,3PC主要有两个改动点:在协调者和参与者之间都引入了超时机制+把准备阶段一分为二

    3PC:CanCommit + PreCommit + DoCommit,具体操作如下

    CanCommit阶段:协调者向参与者发送提交请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

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

    如果协调者从所有参与者获得反馈都是Yes响应,那么就执行事务的预执行;

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

    DoCommit阶段:执行提交或中断事务。当协调者没有收到参与者发送的ACK响应,就会执行中断事务。

    可见,3PC主要解决了2PC的单点问题和同步阻塞问题。

    (二)对于微服务,传统分布式事务存在的问题

    在微服务架构中,传统分布式事务并不是实现数据一致性的最佳选择,主要有三大问题:

    问题一:对于微服务架构来说,数据访问变得更加复杂,为达到微服务间的松耦合和高度独立,数据是微服务私有的,唯一可访问的方式就是通过API,采用2PC/3PC难度太大。

    问题二:不同的微服务经常使用不同的数据库,但是在微服务架构中,服务会产生不同类型的数据,关系数据库不一定是最佳选择,很多微服务会采用SQL和NoSQL结合模式,如搜索引擎、图数据库等NoSQL数据库大多数都不支持2PC/3PC。

    问题三:当数据被拆分了或者在不同的数据库存在重复数据的时候,锁定资源和序列化数据来保证一致性就会变成一个非常昂贵的操作,会给系统的吞吐量以及扩展性带来巨大的挑战。

    对于微服务架构,建议采用一种更为松散的方式来维护一致性,也就是所谓的最终一致性,对于开发者而言,实现最终一致性的方案可以根据不同的业务场景做不同的选择。

    二、CAP理论和BASE思想

    1.CAP理论

    指的是在一个分布式系统中,无法同时实现一致性Consistency、可用性Availability和分区容错性PartitionTolerance。

    对于典型分布式系统而言,如图所以,这三个概念可以做以下解释:

    一致性Consistency:

    指分布式系统中的所有数据备份在同一时刻是否拥有同样的值。

    可用性Availability:

    指在集群中一部分节点故障后,集群整体是否还能正常响应请求。

    分区容错性PartitionTolerance:

    相当于通信的时限要求,系统如果不能在一定时限内达到数据一致性,就意味着发生了分区情况,也就是说整个分布式系统就不在互联了。

    由于当前网络硬件肯定会出现延迟丢包等通信异常问题,三态性不可避免,所以分区容错性必须实现。

    2.BASE思想

    BASE=BasicallyAvailiable(基本可用)+SoftState(软状态)+EventualConsistency(最终一致性)

    BASE理论是对CAP理论的延伸,基本思想是即使无法做到强一致性,应用可以采用适合的方式达到最终一致性。

    BasicallyAvailiable(基本可用):

    指分布式系统在出现故障的时候,可以损失部分可用性,需要保证和核心可用。服务限流和降级就是其基本表现。

    SoftState(软状态):

    指允许系统存在中间状态,而中间状态不会影响整体可用状态。分布式存储中一般一份数据都有有若干个副本,允许不同节点间副本同步的延时就是软状态的体现。

    EventualConsistency(最终一致性):

    指系统中所有的数据副本经过一定时间后,最终能够达到一致的状态。

    CAP的一致性就是强一致性,这种一致性级别是最符合用户直觉的,用户体验好,但实现起来对系统性能影响较大弱一致性正好相反。BASE中的最终一致性可以看做是弱一致性的一种特殊情况。

    3.CAP理论和BASE思想的关联性

    CAP理论和BASE思想实际上是有关联的,基本关系如图所示:                                                          

    CAP理论和BASE思想讨论的意义在于即使无法做到强一致性,我们也可以采用合适的方式达到最终一致性,这点对微服务架构很重要。最终一致性的方法重要有以下六种分别讲解。

    在微服务架构中,比如,对于一个完整的下单操作而言,订单服务和支付服务都是业务闭环中的一部分,在一个完整的业务操作流程中需要保证各自数据的正确性和一致性。

    三、可靠事件模式

    1.基本思路

    尝试将订单和支付两个微服务进行分别管理,并需要一个媒介用于这两个微服务之间进行数据传递,一般而言,消息中间件MOM适合扮演数据传递媒介的角色。引入消息中间件后下单操作流程可以拆分为如下三个步骤:

    (1)用户下单

    当用户使用订单服务下单时,一方面订单服务需要对所产生的订单数据进行持久化操作,另一方面,也需要同时发送一条创建订单的消息到消息中间件。

    (2)交易支付

    当消息中间件接收到订单创建消息,就会把消息发送到支付服务。

    支付服务接收到订单创建消息后,同样对该消息进行业务处理并持久化。当所有关于支付相关的业务逻辑执行完成以后,支付服务需要向消息中间件发送一条支付成功的消息。

    (3)订单更新

    支付成功消息通过消息中间件传递到订单服务时,订单服务根据支付的结果处理后续业务流程,一般涉及订单状态更新、向用户发送通知内容等内容。

    2.关键点

    对于以上三个闭环管理,仔细分析整个过程,不难发现存在如下三个基本问题:

    (1)某个服务在更新了业务实体后发布消息失败;

    (2)服务发布事件成功,但是消息中间件未能正确推送事件到订阅的服务;

    (3)接受事件的服务重复消费事件。

    针对第三个问题,是最为容易解决的,一般处理方法是由业务代码控制幂等性,例如支付服务传入一个订单时,可以通过判断该订单所对应的唯一ID是否已经处理方式来避免对其再次处理。

    但是前两个问题概括起来就是要解决消息传递的可靠性问题,这个是可靠性事件模式实现数据最终一致性的关键点。要做到可靠消息传递,需要消息中间件确保至少投递一次消息,目前主流的消息中间件都支持消息持久化和至少一次投递的功能。所以,我们需要考虑的是,如何原子性的完成业务操作和发布消息。

    订单服务同时需要处理数据持久化和消息发送两个操作,这就需要考虑两个场景:

    (1)如果数据持久化操作失败,显然消息不该被发送;

    (2)如果数据持久化操作成功,但消息发送失败,那么已经被持久化的数据需要被回滚以还原到初始状态。

    对应这两个场景基本实现流程图如下:

    在逻辑上是可行的,但在运行中,需要考虑很多意想不到的场景,主要有以下两个实际问题:

    (1)实际问题一:典型的依旧是分布式环境下所固有的网络通信异常问题,消息中间件返回通信发生故障,如下图分析:              

    (2)实际问题二:订单服务投递消息后等待消息返回,当消息返回时,订单服务挂了,也会导致数据不一致,如下图分析:

    3.解决方案

    解决上面的问题可以使用一个本地事件表。

    微服务在进行业务操作时需要将业务数据和事件保存在同一个本地事务中,由本地事务保证更新业务和发布事件的原子性。

    发布的事件被保存在本地事务表中,然后该服务实时发布一个事件通知关联的业务服务,如果事件发布成功则立即删除本地事件表中的事件。      

    由于事件消息发布可能会失败或无法获取返回结果,我们需要使用一个额外的“事件恢复”服务来恢复事件,该事件恢复服务定时从事件表中恢复未发布成功的事件并重新发布,只有重新发布才删除保存在本地事件表中的事件。

    注意,事件恢复服务保证了事件一定会被发布,从而确保数据的最终一致性。

    4.实现策略

    在实现上,首先考虑在可靠事件模式中存在一个事件生产者。该事件生产者处于操作的主导地位, 并根据业务操作通过事件的方式发送业务操作的结果(在上例中,订单服务就是事件的生产者),其次,事件消费者是被动方,负责根据事件来处理自身业务逻辑(上例中的支付服务属于事件消费者)。

    有了事件生产者和事件消费者后,我们关注事件服务,事件服务的主要作用就是管理本地事件表,它能存储、确认并发送事件,同时根据不同状态查询事件信息并确定事件已被事件消费者成功消费。事件服务有三大组件:       

    (1)事件确认组件

    表现为一种定时机制,用于处理事件没有被成功发送的场景。

    例如,订单服务在完成业务操作之后需要发送事件到本地事件表,如果这个过程中事件没有发送成功,我们就需要对这些事件重新发送,这个过程为事件确认。

    (2)事件恢复组件

    同样表现为一种定时机制,根据本地事件表中的事件状态,专门处理状态为已确认但还没有成功消费且已超时的事件。

    基本的事件恢复策略就是向消费者重新发送事件,并在消费成功后更新事件状态,并在本地事件表中进行逻辑删除。

    (3)实时消息传递组件

    基于特定的消息中间件工具和框架将事件作为消息进行发送的组件。

    目前可供选择的主流消息中间件包括RabbitMQ、ActiveMQ、RocketMQ、Kafka等。

    四、补偿模式

    1.基本思路

    基本思路在于使用一个额外的补偿服务来协调各个需要保证一致性的微服务,补偿服务按顺序依次调用各个微服务,如果某个微服务调用失败就撤销之前所有已经完成的微服务,补偿服务对需要保证一致性的微服务提供补偿操作。

    举例当中涉及两个微服务,订单微服务和支付微服务,为其提供补偿操作,如果支付服务失败,就需要取消之前的下单服务。

    为降低开发的复杂性和提高效率,补偿服务通常实现为一个通用的补偿框架,补偿框架提供服务编排和自动完成补偿的能力。

    2.关键点

    对于补偿服务而言,所有服务的操作记录是一个关键点,操作记录是执行取消操作的前提。

    举例中,订单服务与支付服务需要保存详细的操作记录和日志,这些日志和记录有助于确定失败的步骤和状态,进而明确需要补偿的范围,然后获取所需补偿的业务数据。

    如果只是订单服务失败,那么只需要补偿一个服务就可以,如果支付服务也失败了,对两个服务进行回滚。

    补偿操作要求业务数据包括支付时的业务流水号、账号和金额。理论上可以根据唯一的业务流水号就能完成补偿操作,但提供更多的数据有益于微服务健壮性。

    3.解决方案

    实现补偿模式的关键要素就是记录完整的业务流水,可以通过业务流水为补偿操作提供需要的业务数据。

    补偿服务可以从业务流水的状态中知道补偿的范围,补偿过程中需要的业务数据同样可以从记录的业务流水中获取。

    补偿服务作为一个服务调用过程同样存在调用不成功的情况,需要通过一定的健壮性机制来保证补偿的成功率,补偿的相关操作本身需要具有幂等性。

    补偿服务健壮性策略:需要根据服务执行失败的原因来选择不同的重试策略,如图所示:                                         

    (1)服务重启:如果失败的原因不是暂时的,而是由业务因素导致的业务错误,需要对问题进行修正后重新执行。

    (2)立即重试:对于网络失败或数据库锁等瞬时异常,重试在很大程度上能够确保任务正常执行。

    (3)定时调用:一般会指定调用的次数上限,如果调用次数达到上限也就不再进行重试。

    如果通过服务重启、立即重试、定时调用等策略依旧不能解决问题,则需要通知相关人员进行处理,即人工干预模式。

    五、Sagas长事务模式--错误管理模式,同时用于控制复杂事务的执行和回滚

    1.基本思路

    长时间持续的事务无法简单地通过一些典型的ACID模型以及使用多段提交配合持有锁的方式来实现。Sagas用于解决这个问题,和多段式分布式事务处理不同,Sagas会将工作分成单独的事务,包含正常额操作和回滚的操作。

    对于开发者而言,不是将所有微服务都定义为分布式的ACID事务,以下单行为为例,将其定义为一个整体,其中包含如何去生成订单以及如何去取消订单,对于支付而言也需要提供同样的逻辑。

    可以将订单和支付服务组合在一起构成一个服务链,然后将整个服务链加密,这样只有该服务链的接收者才能够操控这个服务链。

    当一个服务完成后,会将完成的信息记录到一个集合中,之后可以通过这个集合访问到对应的服务。

    当一个服务失败时,服务本身将本地清理完毕并将消息发送给该集合,从而路由到之前执行成功的服务,然后回滚所有的事务。

    2.解决方案

    在Sagas事务模型中,一个长事务是由一个预定义好执行顺序的子事务集合和他们对应的补偿子事务集合所组成。

    典型的一个完整的交易由T1、T2、......、Tn等多个业务活动组成,每个业务活动可以是本地操作或者是远程操作,而每个业务活动都有对应的取消活动C1、C2、......、Cn。

    所有的业务活动在Sagas事务下要么全部成功,要不全部回滚,不存在中间状态。对于一个Sagas链路而言,各个业务活动执行过程中都会依赖上下文,每个业务活动都是一个原子操作,并提供执行和取消两个入口。

    需要设计一个存储模型来保存执行上下文并通过该存储模型来索引到对应的服务。

    存储模型中包含两个内部结构,一个是完成的任务,一个是等待执行的任务。如果成功就会将任务向前执行,如果失败就向后执行。

    实现上的一种思路可以采用队列和栈数据结构,一方面使用队列来向前执行,另一方面使用栈来向后执行。

    注意,当执行取消操作进行事务操作失败时需要记录失败事务日志,通过重试策略进行重试,对重试失败的执行定时重试,在有问题时则进行人工干预。

    六、TCC模式

    1.基本思路

    一个完整的TCC业务由一个主服务和若干个从服务组成,主服务发起并完成整个业务流程。

    从服务提供三个接口:Try、Confirm、Cancel:

    Try接口:完成所有业务规则检查,预留业务资源。

    Confirm接口:真正执行业务,其自身不做任何业务检查,只使用Try阶段预留的业务资源,同时该操作需要满足幂等性。

    Cancel接口:释放Try阶段预留的业务资源,同样也需要满足幂等性。

    举例来看,订单系统拆分成订单下单和订单支付两个场景,使用TCC模式后执行效果如下:

    (1)Try阶段:尝试执行业务。

    一方面完成所有业务检查,如针对该次订单下单操作,需要验证商品的可用性以及用户账户金额是否够。

    另一方面需要预留业务资源,如把用户账户余额进行冻结用于支付该订单,确保不会出现其他并发进程扣减账户余额导致后续支付无法进行。

    (2)Confirm阶段:执行业务。

    Try阶段一切正常,则执行下单操作并扣除用户账号中的支付金额。

    (3)Cancel阶段:取消执行业务。

    释放Try阶段预留的业务资源,如果Try阶段部分成功,如商品可用且正常下单,但账户余额不够而冻结失败,则需要对产品下单做取消操作,释放被占用的该商品。

    2.解决方案

    TCC服务框架不需要记录详细的业务流水,完成Confirm和Cancel操作的业务由业务服务提供。

    TCC模式同样有两个阶段组成

    第一阶段:

    主业务服务分别调用所有从业务的Try操作,并在活动管理器中登记所有从业务服务。当所有从业务服务的Try操作都调用成功或者某个从业务的Try操作失败,进入第二个阶段。

    第二阶段:

    主业务根据第一阶段的执行结果来执行Comfirm或Cancel操作。

    如果第一阶段所有Try操作都成功,则主业务服务调用所有从业务活动的Confirm操作。

    如果第一阶段中失败,则调用Cancel操作。

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

    (1)主业务服务

    整个业务的发起方,在订单处理场景中,订单应用系统即是主业务服务。

    (2)从业务服务

    负责提供TCC业务操作,是整个业务活动的操作方。

    从业务必须实现Try、Confirm和Cancel三个接口,供主业务服务调用。Confirm和Cancel接口需要具备幂等性,订单的下单服务与支付服务即是从业务服务。

    (3)业务活动管理

    管理控制整个业务活动,包括记录维护TCC全局事务状态和每个从业务服务的子事务状态,并在业务活动提交时确认所有从业务服务Confirm操作,在业务活动取消时调用所有从业务服务的Cancel操作。

    3.实现策略

    在实现TCC模式上,最重要的工作是设计一个稳定的、高可用的、扩展性强的TCC事务管理器。

    在一个跨服务的业务操作中,首先通过Try锁住服务中业务资源进行资源预留,只有资源预留成功了,后续的操作才能正常进行。Confirm操作是在Try之后进行的对Try阶段锁定的资源进行业务操作,Cancel在所有操作失败时用于回滚。

    TCC的操作都需要业务方提供对应的功能,在开发成本上比较高,推介TCC框架有:

    (1)http://github.com/protera/spring-cloud-rest-tcc;

    (2)http://github.com/changmingxie/tcc-transaction;

    (3)http://github.com/liuyangming/ByteTCC;

    (4)http://github.com/QNJR-GROUUP/EasyTransaction;

    (5)http://github.com/yu199195/happylifeplat-tcc;

    (6)https://www.atomikos.om/Blog/TCCForTrasationMangementAcrossMicroservices。

    七、最大努力通知模式

    1.基本思路

    本质上是一种通知类的实现方案。

    基本思路是通知发送方在完成业务处理后向通知接收方发送通知消息。

    当消息接收方没有成功消费消息时,消息的发送方还需要进行重复发送直到消费者消费成功或达到某种发送总之条件。

    消息发送方可以设置复杂的通知规则,利于采用阶梯式事件通知方式。

    通知接收方也可以使用发送方所提供的查询和对账接口获取数据,用于恢复通知失败所导致的业务数据。

    以支付宝为例,通知回调商户提供的回调接口,通过多次通知、查询对账等手段完成交易业务平台间的商户通知。

    2.解决方案

    实现上比较简单,基本系统结构中的通知服务包括三大组件:

    (1)查询组件

    通发送方处理业务并把业务记录保存起来,查询组件提供查询入口供通知接收方主动查询业务数据,避免数据丢失。

    (2)确认组件

    当通知接收方成功接收到通知时,需要与通知发送方确认通知已被正常接收。确认组件接收到确认消息之后就会更新业务记录中的状态,通知组件根据状态就不需要再发送通知。

    (3)通知组件

    通知组件根据业务记录向通知接收方发送通知,在发送通知的过程中需要保存通知记录,并根据业务记录的状态以及现有的通知记录确定下一次发送通知的策略。

    注:最大努力通知模式适合于业务最终一致性的时间敏感度比较低的场景,一般用于类似支付宝与商户集成类跨企业的业务活动。

    八、人工干预模式

    1.基本思路

    严格意义上并不是一种数据一致性的实现机制,当前面讲的各种模式都无法满足需要时,人工干预模式更多的是一种替代方案。

    对于一些重要的业务场景下,由于前面几种模式中因为网络三态性无法解决问题的情况,需要人工干预来保证真正的一致性。常用手段为定期对账等。

    2.解决方案

    实施前提是需要一个后台管理系统,提供操作不一致的基本入口。

    周期性的对账机制需求,对账机制基于业务数据,业务双方根据各自系统内所产生的订单或支付记录,相互对比发现数据不一致的情况,然后通过线下付款等形式形成一致的操作结果。

    九、数据一致性模式总结

    对于金融、支付等业务体系,数据一致性要求极高,需要保证严格的实时一致性要求。

    对于基于社交类的应用场景,可以采用局部实时一致、最终全局一致的实现思路。

    微服务架构里面建议“兜底”思维,即不管实现方案是否完美,最后都要有一个备选方案,备选方案不一定满足日常业务场景,但当出现异常情况时,可通过备选完成正常业务的闭环。

    参考书籍、文献和资料:

    【1】郑天民. 微服务设计原理与架构. 北京:人民邮电出版社,2018.05

    【2】尹吉欢. Spring Cloud微服务全栈技术与案例分析. 北京:机械工业出版社,2018.08

    展开全文
  • 分布式事物

    2020-11-18 13:54:57
    一、什么事分布式事物分布式事物,就是在分布式系统中运行的事物,由多个本地事物组成。在分布式场景下,事物可能来自与不同的系统,不同的集群。 分布式事物的基本特性   分布式事物是由多个事物的组合,...

    一、什么事分布式事物?

    分布式事物,就是在分布式系统中运行的事物,由多个本地事物组成。在分布式场景下,事物可能来自与不同的系统,不同的集群。

    分布式事物的基本特性
      分布式事物是由多个事物的组合,那么,事物的特征ACID也就是分布式事务的基本特征。

    原子性(Atomicity),即事务最终的状态只有两种,全部执行成功和全部不执行。若处理事务的任何一项操作不成功,就会导致整个事务失败。一旦操作失败,所有操作都会被取消(即回滚),使得事务仿佛没有被执行过一样。

    一致性(Consistency),是指事务操作前和操作后,数据的完整性保持一致或满足完整性约束。

    隔离性(Isolation),是指当系统内有多个事务并发执行时,多个事务不会相互干扰,即一个事务内部的操作及使用的数据,对其他并发事务是隔离的。

    持久性(Durability),也被称为永久性,是指一个事务完成了,那么它对数据库所做的更新就被永久保存下来了。即使发生系统崩溃或宕机等故障,只要数据库能够重新被访问,那么一定能够将其恢复到事务完成时的状态。

    二、如何实现分布式事物?

    目前,实现分布式事物主要有以下三种方式:

    • 基于 XA 协议的二阶段提交协议方法;
    • 三阶段提交协议方法;
    • 基于消息中间件的最终一致性方法。

    1、基于XA的二阶段提交

      XA可以分为两部分,事物管理器和资源管理器接口。事务管理器作为协调者,负责各个本地资源的提交和回滚;而资源管理器就是分布式事务的参与者,通常由数据库实现,比如 Oracle、DB2 等商业数据库都实现了 XA 接口。

      基于 XA 协议的二阶段提交方法中,二阶段提交协议(The two-phase commitprotocol,2PC),用于保证分布式系统中事务提交时的数据一致性,是 XA 在全局事务中用于协调多个资源的机制。

      二阶段提交协议分为投票(voting)和提交(commit)两个阶段;

      投票阶段:协调者(Coordinator,即事务管理器)会向事务的参与者(Cohort,即本地资源管理器)发起执行操作的 CanCommit 请求,并等待参与者的响应。参与者接收到请求后,会执行请求中的事务操作,记录日志信息但不提交,待参与者执行成功,则向协调者发送“Yes”消息,表示同意操作;若不成功,则发送“No”消息,表示终止操作。

      提交阶段。在提交阶段,协调者会根据所有参与者返回的信息向参与者发送 DoCommit 或 DoAbort 指令:

      若协调者收到的都是“Yes”消息,则向参与者发送“DoCommit”消息,参与者会完成剩余的操作并释放资源,然后向协调者返回“HaveCommitted”消息;

      如果协调者收到的消息中包含“No”消息,则向所有参与者发送“DoAbort”消息,此时发送“Yes”的参与者则会根据之前执行操作时的回滚日志对操作进行回滚,然后所有参与者会向协调者发送“HaveCommitted”消息;协调者接收到“HaveCommitted”消息,就意味着整个事务结束了。

    虽然基于 XA 的二阶段提交算法基本满足了事务的 ACID 特性,但依然有些不足。

    同步阻塞问题:二阶段提交算法在执行过程中,所有参与节点都是事务阻塞型的。也就是说,当本地资源管理器占有临界资源时,其他资源管理器如果要访问同一临界资源,会处于阻塞状态。

    单点故障问题:基于 XA 的二阶段提交算法类似于集中式算法,一旦事务管理器发生故障,整个系统都处于停滞状态。尤其是在提交阶段,一旦事务管理器发生故障,资源管理器会由于等待管理器的消息,而一直锁定事务资源,导致整个系统被阻塞。

    数据不一致问题:在提交阶段,当协调者向参与者发送 DoCommit 请求之后,如果发生了局部网络异常,或者在发送提交请求的过程中协调者发生了故障,就会导致只有一部分参与者接收到了提交请求并执行提交操作,但其他未接到提交请求的那部分参与者则无法执行事务提交。于是整个分布式系统便出现了数据不一致的问题。

    4、三阶段提交方法

      三阶段提交协议(Three-phase commit protocol,3PC),是对二阶段提交(2PC)的改进。为了解决两阶段提交的同步阻塞和数据不一致问题,三阶段提交引入了超时机制和准备阶段。

      CanCommit阶段,CanCommit 阶段与 2PC 的投票阶段类似:协调者向参与者发送请求操作(CanCommit请求),询问参与者是否可以执行事务提交操作,然后等待参与者的响应;参与者收到CanCommit 请求之后,回复 Yes,表示可以顺利执行事务;否则回复 No。

      PreCommit阶段,协调者根据参与者的回复情况,来决定是否可以进行 PreCommit 操作。

    如果所有参与者回复的都是“Yes”,那么协调者就会执行事务的预执行:
      发送预提交请求。协调者向参与者发送 PreCommit 请求,进入预提交阶段。
      事务预提交。参与者接收到 PreCommit 请求后执行事务操作,并将 Undo 和 Redo信息记录到事务日志中。
      响应反馈。如果参与者成功执行了事务操作,则返回 ACK 响应,同时开始等待最终指令。

    假如任何一个参与者向协调者发送了“No”消息,或者等待超时之后,协调者都没有收到参与者的响应,就执行中断事务的操作:
      发送中断请求。协调者向所有参与者发送“Abort”消息。
      终断事务。参与者收到“Abort”消息之后,或超时后仍未收到协调者的消息,执行事务的终断操作。

      预执行阶段,不同节点上事务执行成功和失败的流程,如下所示。

      DoCmmit 阶段进行真正的事务提交,根据 PreCommit 阶段协调者发送的消息,进入执行提交阶段或事务中断阶段。

    执行提交阶段:
      **发送提交请求。协调者接收到所有参与者发送的 Ack 响应,从预提交状态进入到提交状态,并向所有参与者发送 DoCommit 消息。
      事务提交。参与者接收到 DoCommit 消息之后,正式提交事务。完成事务提交之后,释放所有锁住的资源。
      响应反馈。参与者提交完事务之后,向协调者发送 Ack 响应。完成事务。协调者接收到所有参与者的 Ack 响应之后,完成事务。

    事务中断阶段:
      发送中断请求。协调者向所有参与者发送 Abort 请求。
      事务回滚。参与者接收到 Abort 消息之后,利用其在 PreCommit 阶段记录的 Undo信息执行事务的回滚操作,并释放所有锁住的资源。
      反馈结果。参与者完成事务回滚之后,向协调者发送 Ack 消息。
      终断事务。协调者接收到参与者反馈的 Ack 消息之后,执行事务的终断,并结束事务。

      执行阶段不同节点上事务执行成功和失败 (事务终断) 的流程,如下所示。在 DoCommit 阶段,当参与者向协调者发送 Ack 消息后,如果长时间没有得到协调者的响应,在默认情况下,参与者会自动将超时的事务进行提交,不会像两阶段提交那样被阻塞住

    3、基于分布式消息的最终一致性方案

      2PC 和 3PC 这两种方法,有两个共同的缺点,一是都需要锁定资源,降低系统性能;二是,没有解决数据不一致的问题。因此,便有了通过分布式消息来确保事务最终一致性的方案。

      在 eBay 的分布式系统架构中,架构师解决一致性问题的核心思想就是:将需要分布式处理的事务通过消息或者日志的方式异步执行,消息或日志可以存到本地文件、数据库或消息队列中,再通过业务规则进行失败重试。这个案例,就是使用基于分布式消息的最终一致性方案解决了分布式事务的问题。终断事务。协调者接收到参与者反馈的 Ack 消息之后,执行事务的终断,并结束事务。

    引用:极客时间读书笔记

    展开全文
  • 分布式事物.txt

    2019-05-22 16:50:00
    微服务分布式事物视频详解,TCC,BASE,MQ,2PC,最终一致
  • 此代码是springboot项目,该项目内集成了多数据源和分布式事物,集合mybatis数据库持久层,集成了mybatis分页插件,事物拦截配置,页面模板引擎
  • TCC实现分布式事物,实现多数据源,多应用事物统一管理。代码过多,需经验丰富
  • 分布式事物相关概念

    2019-01-03 10:02:55
    分布式事物 分布式事物分布式事物是指事物的参与者、支持事物的服务器、资源服务器以及事物管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同小操作组成,这些小操作分布在不同的...

    分布式事物

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

    本地事物

    事物的ACID是通过InnoDB日志和锁来保证。事物的隔离性是通过数据库的机制实现的,持久性是通过Redo Log(重做日志)来实现,原子性和一致性通过Undo Log来实现。

    Undo Log的原理很简单,为了满足事物的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为 Undo Log),然后进行数据修改。如果出现了错误或者用户执行了 Rollback 语句,系统可以利用 Undo Log 中备份的数据将数据恢复到事物开始之前的状态。和 Undo Log 相反,Redo Log 记录的是新数据的备份,在事物提交之前,只要将 Redo Log 中的数据持久化即可,不需要讲数据持久化。

    数据库中事物的四大特性 ACID

    A 原子性:一个事物中的所有操作,要么全部成功,要么全部失败。

    C 一致性:一个事物执行之前和执行之后数据库都必须处于抑制状态。(转账,转出账号的和转入账号的总金额一致)

    I 隔离性:不同事物同时操作相同数据,每个事物都有各自的完整数据空间。(互不干涉)

    D 持久性:事物结束后,数据持久化到数据库

     

    展开全文
  • 多数据源根据XA实现,分布式事物,通过统一事物开始,事物提交,失败事物回滚,直接就可以运行
  • 文章目录数据库事务数据库事务的特性事物隔离级别脏读、不可重复读、幻读分布式事务分布式事务产生的原因Service 多个节点Resource多个节点分布式事物基础CAP定理BASE理论一、2PC (两阶段提交)二、3PC (三阶段...

    数据库事务

    数据库事务的特性

    原子性(Atomicity )、一致性( Consistency )、隔离性( Isolation)和持久性(Durabilily),简称就是ACID。

    • Atomicity(原子性):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

    • Consistency(一致性):事务开始前和结束后,数据库的完整性约束没有被破坏 。

    • Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。

      事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

    • Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

    事物隔离级别

    MySQL 的事务隔离是在 MySQL.ini 配置文件里添加的,在文件的最后添加:

    transaction-isolation = REPEATABLE-READ
    
    • READ-UNCOMMITTED:读-未提交,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。
    • READ-COMMITTED:读-已提交,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读)。
    • REPEATABLE-READ:可重复读,默认级别,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读)。
    • SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

    脏读、不可重复读、幻读

    • 脏读 : 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

    • 不可重复读 : 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

    • 幻读 : 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

    • 小结 : 不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

    分布式事务

    分布式事务产生的原因

    从上面本地事务来看,我们可以分为两块:

    Service 产生多个节点 (服务)

    随着互联网快速发展,微服务,SOA等服务架构模式正在被大规模的使用,举个简单的例子,一个公司之内,用户的资产可能分为好多个部分,比如余额,积分,优惠券等等。在公司内部有可能积分功能由一个微服务团队维护,优惠券又是另外的团队维护。这样的话就无法保证积分扣减了之后,优惠券能否扣减成功。

    在这里插入图片描述

    Resource 产生多个节点 (存储)

    同样的,互联网发展得太快了,我们的Mysql一般来说装千万级的数据就得进行分库分表,对于一个支付宝的转账业务来说,你给的朋友转钱,有可能你的数据库是在北京,而你的朋友的钱是存在上海,所以我们依然无法保证他们能同时成功。
    在这里插入图片描述

    分布式事物基础

    分布式事务是随着互联网高速发展应运而生的,数据库的 ACID 四大特性,已经无法满足我们分布式事务,这个时候又提出一些新的理论。

    CAP定理

    CAP定理指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼
    在这里插入图片描述

    • 一致性(Consistency) :更新操作成功后,所有节点在同一时间的数据完全一致。

    • 可用性(Availability) : 用户访问数据时,系统是否能在正常响应时间返回结果。

    • 分区容错性(Partition tolerance) : 分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。

    BASE理论

    BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually Consistent (最终一致性)三个短语的缩写,是对 CAP中AP的一个扩展。

    • Basically Available(基本可用):分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。

    • Soft state(软状态):允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是 CAP 中的不一致。

    • Eventually Consistent (最终一致性):最终一致是指经过一段时间后,所有节点数据都将会达到一致。

    BASE 解决了 CAP 中理论没有网络延迟,在 BASE 中用软状态和最终一致性,保证了延迟后的一致性。

    BASE 和 ACID 是相反的,它完全不同于 ACID 的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。

    一、2PC (两阶段提交)

    两阶段提交(Two-phase Commit,2PC),通过引入协调者来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。

    1、准备阶段

    协调者询问参与者事务是否执行成功,参与者发回事务执行结果。
    在这里插入图片描述

    2、提交阶段

    如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。

    需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。
    在这里插入图片描述

    3、优点

    • 原理简单

    • 实现方便

    4、缺点

    • 同步阻塞: 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。
    • 单点问题: 协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。
    • 网络分区导致数据不一致: 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
    • 太过保守: 任意一个节点失败就会导致整个事务失败,没有完善的容错机制。

    二、3PC (三阶段提交)

    三阶段提交(Three-phase commit),也叫三阶段提交协议(Three-phase commit protocol),是二阶段提交(2PC)的改进版本。2PC 和 3PC 都是数据库层面的。
    在这里插入图片描述

    与两阶段提交不同的是,三阶段提交有两个改动点。

    1. 在协调者和参与者中都引入超时机制。
    2. 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

    也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

    1、CanCommit阶段

    协调者向参与者发送commit请求,参与者如果可以提交就返回Yes,否则返回No。

    2、PreCommit阶段

    协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。

    • 假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
    • 假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。

    3、doCommit阶段

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

    • 执行提交
    • 中断事务

    需要注意的是,一旦进入阶段三,可能会存在以下两种故障。

    • 协调者出现问题。
    • 协调者和参与者之间的网络出现故障。

    无论出现哪种情况,最终都会导致参与者无法及时接收到来自协调者的doCommit或是abort请求,针对这样的异常情况,参与者都会在等待超时之后,继续进行事务提交。

    4、优点

    相较于二阶段提交协议,三阶段提交协议最大的优点就是降低了参与者的阻塞范围,并且能够在出现单点故障后继续达成一致

    5、缺点

    三阶段提交协议在去除阻塞的同时也引入了新的问题,那就是在参与者接收到preCommit消息后,如果网络出现分区,此时协调者所在的节点和参与者无法进行正常的网络通信,在这种情况下,该参与者依然会进行事务的提交,这必然出现数据的不一致

    三、TCC(Try - Confirm - Cancel

    2PC 和 3PC 都是数据库层面的,而 TCC 是业务层面的分布式事务,就像我前面说的分布式事务不仅仅包括数据库的操作,还包括发送短信等,这时候 TCC 就派上用场了!

    TCC 指的是Try - Confirm - Cancel。

    • Try 指的是预留,即资源的预留和锁定,注意是预留。
    • Confirm 指的是确认操作,这一步其实就是真正的执行了。
    • Cancel 指的是撤销操作,可以理解为把预留阶段的动作撤销了。

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

    这种处理方式的前提是面对事务都要有一套确认事务执行的业务,一套取消执行的业务(即补偿业务)。比如说减库存这个业务,确认事务就是减库存,补偿事务就是加库存。

    这种处理方式时所有业务都开始执行,互相不等待,完成了就提交,解决了两阶段提交问题中数据大面积锁定的情况,但是如果业务A已经提交了,但是业务B失败了,没关系,会调用所有的补偿事务,这种解决方案不是靠事务回滚的方式,靠的是事务的补偿。

    还有一点要注意,撤销和确认操作的执行可能需要重试,因此还需要保证操作的幂等。
    在这里插入图片描述
    可以看到流程还是很简单的,难点在于业务上的定义,对于每一个操作你都需要定义三个动作分别对应Try - Confirm - Cancel。

    优点:相对于 2PC、3PC ,TCC 适用的范围更大,不过也因为是在业务上实现的,所以TCC可以跨数据库、跨不同的业务系统来实现事务。

    缺点:解决了业务问题,但是使得业务变得复杂了,写一个业务必须写一个确定执行业务方法和一个补偿业务方法,除此之外还要考虑补偿方案的失败问题,当补偿方案也执行失败了呢,这时候就要考虑重试问题、人工介入问题。

    综上,在电商行业中适用的还是TCC,虽然业务变得复杂了,但是行之有效;如果是转账业务,适合异步确保,转账业务只需要消息可靠就可以,执行时间晚一点也无妨,所以异步确保的关键点是消息的可靠

    四、本地消息表(异步确保)

    在这里插入图片描述
    本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。

    具体怎么做呢?

    1. 消息生产方(也就是发起方),需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。如果消息发送失败,会进行重试发送。
    2. 消息消费方(也就是发起方的依赖方),需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会进入定时任务重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。
    3. 如果调用失败,后台定时任务定时扫描本地消息表,把还没处理完成的消息进行重试或者失败的消息再发送一遍。重试就得保证对应服务的方法是幂等的,而且一般重试会有最大次数,超过最大次数可以记录下报警让人工处理。

    实例:
    在这里插入图片描述
    可以看到本地消息表其实实现的是最终一致性,容忍了数据暂时不一致的情况。

    • 优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。
    • 缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

    五、MQ事务消息

    RocketMQ 就很好的支持了消息事务,让我们来看一下如何通过消息实现事务。
    在这里插入图片描述
    第一步先给 Broker 发送事务消息即半消息,半消息不是说一半消息,而是这个消息对消费者来说不可见,然后发送成功后发送方再执行本地事务。

    再根据本地事务的结果向 Broker 发送 Commit 或者 RollBack 命令。

    并且 RocketMQ 的发送方会提供一个反查事务状态接口,如果一段时间内半消息没有收到任何操作请求,那么 Broker 会通过反查接口得知发送方事务是否执行成功,然后执行 Commit 或者 RollBack 命令。

    如果是 Commit 那么订阅方就能收到这条消息,然后再做对应的操作,做完了之后再消费这条消息即可。

    如果是 RollBack 那么订阅方收不到这条消息,等于事务就没执行过。

    可以看到通过 RocketMQ 还是比较容易实现的,RocketMQ 提供了事务消息的功能,我们只需要定义好事务反查接口即可。

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

    • 缺点: 实现难度大,主流MQ不支持,RocketMQ事务消息部分代码也未开源。

    六、提供回滚接口(同步执行)

    1. 订单系统生成订单号,扔给一个差错恢复系统(存储在自己的db)
    2. 订单系统拿订单号调用库存系统,如果失败,则回滚库存(不管回滚成功或者失败,都通知前台失败)
    3. 订单系统拿订单号调用优惠券系统减少优惠券,如果失败,则回滚库存、回滚优惠券(不管回滚成功或者失败,都通知前台失败)
    4. 开启本地事物,创建订单记录

    差错恢复系统每隔30秒捞取db中订单号,查询订单系统。

    1. 如果订单记录ok,说明数据全部一致
    2. 如果没有订单记录,则根据订单号查询库存系统,如果库存已经回滚,则ok,否则调用库存回滚接口,重试直到成功
    3. 如果没有订单记录,则根据订单号查询优惠券系统,如果优惠券已经回滚,则ok,否则调用优惠券回滚接口,重试直到成功

    总结:这种方式缺点比较多,通常在复杂场景下是不推荐使用的,除非是非常简单的场景,非常容易提供回滚,而且依赖的服务也非常少的情况。

    这种实现方式会造成代码量庞大,耦合性高。而且非常有局限性,因为有很多的业务是无法很简单的实现回滚的,如果串行的服务很多,回滚的成本实在太高。

    总结

    可以看出 2PC 和 3PC 是一种强一致性事务,不过还是有数据不一致,阻塞等风险,而且只能用在数据库层面。

    而 TCC 是一种补偿性事务思想,适用的范围更广,在业务层面实现,因此对业务的侵入性较大,每一个操作都需要实现对应的三个方法。

    本地消息、事务消息其实都是最终一致性事务,因此适用于一些对时间不敏感的业务。

    展开全文
  • springboot + mybatis + atomikos 多数据源分布式事物管理;springboot + mybatis + atomikos 多数据源分布式事物管理
  • 分布式事物实现

    2018-10-22 18:05:52
    一、TCC编程方式Rocketmq采用的这种方式 分为Try - confirm -cancel 三种方式 如下单 try去扣除...二、LCN实现分布式事物 atomikos https://blog.csdn.net/sosfnima/article/details/51970829   分布式事物 ...
  • 分布式事物设计

    2019-06-10 21:51:54
    一、下面方式有什么问题? try{ 1、插入数据库 2、发送消息到MQ(超时情况) 3、提交数据库插入 }catch(){ 回滚插入数据库 ...当发送MQ超时时,并不代表就是发送失败...1、刚性分布式事物:强一致性,CAP中的CP模...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,419
精华内容 22,967
关键字:

分布式事物