当前位置:   article > 正文

分布式事务一致性

分布式事务一致性

分布式事务指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。

单个事务ACID,怎么实现的?AC(undo redo 日志) CI(lock 锁)。

原子性:,原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。

隔离性:隔离性是指多个事务并发执行的时候,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性: 持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。

一致性:事务执行前后。a和b 账户的总额和执行前一致。

例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。银行卡在其他平台充值时,

对于分布式事务理论:

CAP 理论在分布式系统中

  • 一致性:分布式环境下多个节点的数据是否强一致(客户端知道一系列的操作都会同时发生(生效)
  • 可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果(每个操作都必须以可预期的响应结束)
  • 分区容忍性:特指对网络分区的容忍性(分区容忍性又是不可或缺的)

什么是幂等性

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

1. 传统应用的事务管理

一、两阶段提交(2PC)

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

1.1 准备阶段

协调者询问参与者事务是否执行成功,参与者发回事务执行结果。

1.2 提交阶段

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

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

存在问题:

2.1 同步阻塞 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。

2.2 单点问题 协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。(默认超时,会认为成功了)

2.3 数据不一致 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致(人工手动补偿)。还有各个参与者都要保证不出现问题。

二、补偿事务(TCC)

TCC模式的具体流程为两个阶段:

  1. Try,业务服务完成所有的业务检查(业务逻辑 ),预留必需的业务资源(数据落库,提交了事务。二阶段提交时,没有落库,要等事务管理器,返回响应才落库)

  2. 如果Try在所有服务中都成功,那么执行Confirm操作,Confirm操作不做任何的业务检查(因为try中已经做过),只是用Try阶段预留的业务资源进行业务处理;否则进行Cancel操作,Cancel操作释放Try阶段预留的业务资源。

这么说可能比较模糊,下面我举一个具体的例子,小明在线从招商银行转账100元到广发银行。这个操作可看作两个服务,服务a从小明的招行账户转出100元,服务b从小明的广发银行帐户汇入100元。

服务a(小明从招行转出100元): freeze 为冻结资金,资金操作是,会把需要转出的资金先冻结起来。

  1. try: update cmb_account set balance=balance-100, freeze=freeze+100 where
  2. acc_id=1 and balance>100;
  3. confirm: update cmb_account set freeze=freeze-100 where acc_id=1;
  4. cancel: update cmb_account set balance=balance+100, freeze=freeze-100 where
  5. acc_id=1;

服务b(小明往广发银行汇入100元):

  1. try: update cgb_account set freeze=freeze+100 where acc_id=1;
  2. confirm: update cgb_account set balance=balance+100, freeze=freeze-100 where
  3. acc_id=1;
  4. cancel: update cgb_account set freeze=freeze-100 where acc_id=1;
  1. 首先在 Try 阶段,要先调用远程接口把 a和 b 的钱给冻结起来。
  2. 在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。
  3. 如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

缺点:

 缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。

三,本地消息表(异步确保)

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

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

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

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



undo 和 redo 日志

这两个日志可以保证mysql数据库事务。

相当于镜像备份,出现异常就还原。

1. Seata 概述

http://seata.io/zh-cn/docs/overview/what-is-seata.html

seata:模式:AT,TCC,SAGA .XA

  • AT模式: AT 模式的一阶段、二阶段提交和回滚(借助undo_log表来实现)均由 Seata 框架自动生成,用户只需编写“业务SQL”,便能轻松接入分布式事务,AT 模式是一种对业务无任何侵入的分布式事务解决方案。
  • TTC模式: 相对于 AT 模式,TCC 模式对业务代码有一定的侵入性,但是 TCC 模式无 AT 模式的全局行锁,TCC 性能会比 AT模式高很多。适用于核心系统等对性能有很高要求的场景。
  • SAGA模式:Sage 是长事务解决方案,事务驱动,使用那种存在流程审核的业务场景,如: 金融行业,需要层层审核。
  • XA模式: XA模式是分布式强一致性的解决方案,但性能低而使用较少。

一个分布式的全局事务,整体是两阶段提交Try-[Comfirm/Cancel] 的模型。在Seata中,AT模式与TCC模式事实上都是两阶段提交的具体实现。他们的区别在于:

AT 模式基于支持本地 ACID 事务 的 关系型数据库(目前支持Mysql、Oracle与PostgreSQL):

一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。 二阶段 commit 行为:马上成功结束,自动异步批量清理回滚日志。 二阶段 rollback 行为:通过回滚日志,自动生成补偿操作,完成数据回滚。

相应的,TCC 模式,不依赖于底层数据资源的事务支持:

一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。 二阶段 commit 行为:调用 自定义的 commit 逻辑。 二阶段 rollback 行为:调用 自定义的 rollback 逻辑。

所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

简单点概括,SEATA的TCC模式就是手工的AT模式,它允许你自定义两阶段的处理逻辑而不依赖AT模式的undo_log。


Seata 是阿里开源的分布式事务框架,属于二阶段提交模式。

微服务架构中,这3个模块会变为3个独立的微服务,各自有自己的数据源,调用逻辑就变为:

「推荐」阿里开源的分布式事务框架 Seata

Seata 如何处理呢?

「推荐」阿里开源的分布式事务框架 Seata

Business 是业务入口,在程序中会通过注解来说明他是一个全局事务,这时他的角色为 TM(事务管理者)。

Business 会请求 TC(事务协调器,一个独立运行的服务),说明自己要开启一个全局事务,TC 会生成一个全局事务ID(XID),并返回给 Business。

Business 得到 XID 后,开始调用微服务,例如调用 Storage。

「推荐」阿里开源的分布式事务框架 Seata

(和上面的图一样,方便查看,防止滚到到这儿时已经看不到上面的图片了)

Storage 会收到 XID,知道自己的事务属于这个全局事务。Storage 执行自己的业务逻辑,操作本地数据库。

Storage 会把自己的事务注册到 TC,作为这个 XID 下面的一个分支事务,并且把自己的事务执行结果也告诉 TC。

此时 Storage 的角色是 RM(资源管理者),资源是指本地数据库。

Order、Account 的执行逻辑与 Storage 一致。

在各个微服务都执行完成后,TC 可以知道 XID 下各个分支事务的执行结果,TM(Business) 也就知道了。

Business 如果发现各个微服务的本地事务都执行成功了,就请求 TC 对这个 XID 提交,否则回滚。

TC 收到请求后,向 XID 下的所有分支事务发起相应请求。

各个微服务收到 TC 的请求后,执行相应指令,并把执行结果上报 TC。

重要机制

(1)全局事务的回滚是如何实现的呢?

Seata 有一个重要的机制:回滚日志

每个分支事务对应的数据库中都需要有一个回滚日志表 UNDO_LOG,在真正修改数据库记录之前,都会先记录修改前的记录值,以便之后回滚。

在收到回滚请求后,就会根据 UNDO_LOG 生成回滚操作的 SQL 语句来执行。

如果收到的是提交请求,就把 UNDO_LOG 中的相应记录删除掉。

(2)RM 是怎么自动和 TC 交互的?

是通过监控拦截JDBC实现的,例如监控到开启本地事务了,就会自动向 TC 注册、生成回滚日志、向 TC 汇报执行结果。

(3)二阶段回滚失败怎么办?

例如 TC 命令各个 RM 回滚的时候,有一个微服务挂掉了,那么所有正常的微服务也都不会执行回滚,当这个微服务重新正常运行后,TC 会重新执行全局回滚。

再从宏观上梳理一下 Seata 的工作过程:

「推荐」阿里开源的分布式事务框架 Seata

  • TM 请求 TC,开始一个新的全局事务,TC 会为这个全局事务生成一个 XID。
  • XID 通过微服务的调用链传递到其他微服务。
  • RM 把本地事务作为这个XID的分支事务注册到TC。
  • TM 请求 TC 对这个 XID 进行提交或回滚。
  • TC 指挥这个 XID 下面的所有分支事务进行提交、回滚。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/858468
推荐阅读
相关标签
  

闽ICP备14008679号