分布式事务

1. 事务

提供一种要不什么也不做,要么做全套的机制 ALL Or Nothing

事务的作用

保持数据的一致性

事务的ACID四大特性

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

事务的并发问题

脏读:
事务A读取了事务B更新的数据,事务B未提交并回滚数据,那么A读取到的数据是脏数据
不可重复读:
事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
幻读:
系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A更改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

MYSQL的事务隔离级别

读未提交 出现脏读 读到未提交的信息
读已提交 出现不可重复读, 数据一提交,commit其他线程就可以读到,读取数据不一致
可重复读 出现幻读 幻读发生在其他线程对增删时,你修改数据就会出行,新增的数据不发生改变
串行化 悲观锁,锁表

事务的传播行为

spring 定义了七种传播行为,参考TransactionDefinition类

  1. required(必须的): 如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入这个事务
  2. supports(支持的): 如果调用者有事务,就加入事务,没有事务就,不创建事务
  3. mandatory(强制的): 调用这个,传播行为定义的,必须包含事务,否则不允许调用 抛出异常
  4. required_new(必须创建新事务): 新建事务,不管调用者是否有事务,都挂起,执行自己的事务
  5. not_supports(不支持): 不支持事务,有事务挂起,执行完后,继续事务
  6. never(绝不): 不可以有事务,有事务就报错
  7. nested :如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。(外层事务抛出异常回滚,那么内层事务必须回滚,反之内层事务并不影响外层事务)

本地事务

本地事务有这么几个特征:

  1. 一次事务只连接一个支持事务的数据库(一般来说都是关系型数据库)
  2. 事务的执行结果保证ACID
  3. 会用到数据库锁
起初,事务仅限于对单一数据库资源的访问控制,架构服务化以后,事务的概念延伸到了服务中。倘若将一个单一的服务操作作为一个事务,那么整个服务操作只能涉及一个单一的数据库资源,这类基于单个服务单一数据库资源访问的事务,被称为本地事务(Local Transaction)。

2 分布式事务

在这里插入图片描述

什么是分布式事务

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

什么是分布式系统

部署在不同节点上的系统,通过网络交互来完成协同工作的系统

分布式事务的应用场景

电商、金融、教育、 SNS系统

CAP 定理

CAD定义又称为布鲁尔定理,指一个分布式系统的一致性(Consistency),可用性(Availability),分区容错性(Partition tolerance)

这三个要素最多只能同时实现两点,不可能三者兼顾。分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。

**C (一致性Consistency):**在分布式系统中的所有数据备份,在同一时刻是否同样的值。
① 强一致性
简言之,在任意时刻,所有节点中的数据是一样的。
② 弱一致性
数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。最终一致性就属于弱一致性。
**A (可用性Availability):**在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。
**P (网络分区容错性Partition tolerance):**以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

CA 满足一致性和可用性,放弃分区容错性。
说白了,就是一个单体应用。
CP 满足一致性和分区容错性,放弃可用性。
当系统被分区,为了保证一致性,必须放弃可用性,停止所有服务。
AP 满足可用性和分区容错性,放弃一致性。
当出现分区同时为了保证可用性,必须让节点继续对外服务,这就意味着你的系统在并发访问的时候,可能出现数据不一致的情况。
在分布式系统设计中AP的应用较多,即保证分区容忍性和可用性,牺牲数据的强一致性(写操作后立刻读取到最新数据),保证数据最终一致性(弱一致性)。

3 分布式事务的解决方案

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

  1. X/Open 组织(即现在的 Open Group )定义了分布式事务处理模型
  2. XA协议:XA是一个分布式事务协议。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。
    流程
    投票阶段:参与者将操作结果通知协调者,
    提交阶段:收到参与者的通知后,协调者在向参与者发出通知,根据反馈情况各个参与者是否提交还是回滚;

实际应用交互流程

2PC两阶段提交的正向流程
第一阶段:

2PC中包含着两个角色:事务协调者事务参与者。让我们来看一看他们之间的交互流程:

在分布式事务的第一阶段,作为事务协调者的节点会首先向所有的参与者节点发送Prepare请求。
在接到Prepare请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。如果参与者执行成功,暂时不提交事务,而是向事务协调节点返回“完成”消息。
当事务协调者接到了所有参与者的返回消息,整个分布式事务将会进入第二阶段。

第二阶段:

在2PC分布式事务的第二阶段,如果事务协调节点在之前所收到都是正向返回,那么它将会向所有事务参与者发出Commit请求。
接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。
当事务协调者接收到所有事务参与者的“完成”反馈,整个分布式事务完成。

失败情况的处理流程
第一阶段:

第二阶段:

在这里插入图片描述

在2PC的第一阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。
于是在第二阶段,事务协调节点向所有的事务参与者发送Abort(中止)请求。接收到Abort请求之后,各个事务参与者节点需要在本地进行事务的回滚操作,回滚操作依照Undo Log来进行。
以上就是2PC两阶段提交协议的详细过程。
3. 2PC两阶段提交究竟有哪些不足呢?

  1. 性能问题
    2PC遵循强一致性。在事务执行过程中,各个节点占用着数据库资源,只有当所有节点准备完毕,事务协调者才会通知提交,参与者提交后释放资源。这样的过程有着非常明显的性能问题。
  2. 协调者单点故障问题
    2PC模型的核心,一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知,参与者会一直处于中间状态无法完成事务。
  3. 丢失消息导致的不一致问题。
    第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。

代码补偿事务(TCC)

在这里插入图片描述

TCC是Try ( 尝试 ) — Confirm(确认) — Cancel ( 取消 ) 的简称:
TCC两阶段提交与XA两阶段提交的区别
XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。
TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
其核心在于将业务分为两个操作步骤完成。不依赖 RM 对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。
在这里插入图片描述

本地消息表 (异步确保)事务的最终一致性

这种实现方式的思路,其实是源于 ebay,后来通过支付宝等公司的布道,在业内广泛使用。其基本的设计思想是将远程分布式事务拆分成一系列的本地事务。如果不考虑性能及设计优雅,借助关系型数据库中的表即可实现。
• 订单系统新增一条消息表,将新增订单和新增消息放到一个事务里完成,然后通过轮询的方式去查询消息表,将消息推送到 MQ,库存系统去消费 MQ。

在这里插入图片描述
• 执行流程:

  1. 订单系统,添加一条订单和一条消息,在一个事务里提交。
  2. 订单系统,使用定时任务轮询查询状态为未同步的消息表,发送到 MQ,如果发送失败,就重试发送。
  3. 库存系统,接收 MQ 消息,修改库存表,需要保证幂等操作。
  4. 如果修改成功,调用 RPC 接口修改订单系统消息表的状态为已完成或者直接删除这条消息。
  5. 如果修改失败,可以不做处理,等待重试。
  6. 订单系统中的消息有可能由于业务问题会一直重复发送,所以为了避免这种情况可以记录一下发送次数,当达到次数限制之后报警,人工接入处理;库存系统需要保证幂等,避免同一条消息被多次消费造成数据一致。
  7. 本地消息表这种方案实现了最终一致性,需要在业务系统里增加消息表,业务逻辑中多一次插入的 DB 操作,所以性能会有损耗,而且最终一致性的间隔主要由定时任务的间隔时间决定。

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

MQ事务消息

有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持。
在这里插入图片描述
具体流程如下

  1. Producer 向 MQ 服务器 发送消息 , MQ Server 将消息状态标记为 Prepared(预备状态),注意此时这条消息消费者(MQ订阅方)是无法消费到的。
  2. MQ 服务器收到消息并持久化成功之后,会向Producer 确认首次消息发送成功,此时消息处于 half message(半消息) 状态,并未发送给对应的 Consumer 。
  3. Producer 开始执行本地事务逻辑 , 通过本地数据库事务控制。
  4. 根据事务执行结果,Producer 向 MQ 服务器提交二次确认 ( commit 或者 rollback) 。MQ Server 收到 Commit 状态则将半消息标记为可投递,Consumer 最终将收到该消息;MQ Server 收到 Rollback 状态则删除半消息,Consumer 将不会接受该消息。
  5. 在断网或者应用重启的情况下,二次确认未成功的发给 MQ Server,MQ Server 会主动向 Producer 启动消息回查
  6. Producer 根据事务执行结果,对消息回查返回对应的结果。
  7. Mq Server根据返回结果,决定继续投递消息或者丢弃消息(重复第4步操作)。

注意 1-4 为事务消息的发送过程, 5-6 为事务消息的回查过程。
优点: 实现了最终一致性,不需要依赖本地数据库事务。
缺点: 目前主流MQ中只有RocketMQ支持事务消息。

seata

Seata是阿里开源的一个分布式事务框架,能够让大家在操作分布式事务时,像操作本地事务一样简单。一个注解搞定分布式事务。
解决分布式事务问题,有两个设计初衷

  • 对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入
  • 高性能:减少分布式事务解决方案所带来的性能消耗
    Seata中有两种分布式事务实现方案,AT及TCC
  • AT模式主要关注多 DB 访问的数据一致性,当然也包括多服务下的多 DB 数据访问一致性问题 2PC-改进
  • TCC 模式主要关注业务拆分,在按照业务横向扩展资源时,解决微服务间调用的一致性问题

AT模式(Automatic (Branch) Transaction Mode)

  • Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并决定全局事务的提交或回滚。
  • Transaction Manager(TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
  • Resource Manager (RM):资源管理器,负责本地事务的注册,本地事务状态的汇报(投票),并且负责本地事务的提交和回滚。
  • XID:一个全局事务的唯一标识
    其中,TM是一个分布式事务的发起者和终结者,TC负责维护分布式事务的运行状态,而RM则负责本地事务的运行。
    如下图所示:
    在这里插入图片描述
    下面是一个分布式事务在Seata中的执行流程:
  1. TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID
  2. XID 在微服务调用链路的上下文中传播。
  3. RM 向 TC 注册分支事务,接着执行这个分支事务并提交(重点:RM在第一阶段就已经执行了本地事务的提交/回滚),最后将执行结果汇报给TC
  4. TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。
  5. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
    Seata 中有三大模块,分别是 TM、RM 和 TC。 其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署。
    阿里云GTS,商业付费版。

MT模式(Manual (Branch) Transaction Mode)

Seata还支持MT模式。MT模式本质上是一种TCC方案,业务逻辑需要被拆分为 Prepare/Commit/Rollback 3 部分,形成一个 MT 分支,加入全局事务。如图所示:


MT 模式一方面是 AT 模式的补充。另外,更重要的价值在于,通过 MT 模式可以把众多非事务性资源纳入全局事务的管理中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值