分布式事务

事务

原子性(Atomicity) 全完成或全不完成
一致性(Correspondence) 执行前后状态不能变
隔离性(Isolation) 2个事务不能冲突
持久性(Durability) 完成后持久

隔离级别

Read uncommitted(未提交可读)
Read committed(提交后可读)
Repeatable read(可重复读,读锁)
Serializable(串行化)
在这里插入图片描述

MVCC方法

  • 概念
    是一种并发控制的方法。英文全称为Multi-Version Concurrency Control,乐观锁为理论基础的MVCC(多版本并发控制),MVCC的实现没有固定的规范。每个数据库都会有不同的实现方式。

  • 作用
    不加锁,解决读写冲突,实现读锁的效果。(乐观锁,非阻塞并发读)

mysql实现方案

mysql中,innodb采用了MVCC(多版本并发控制)来解决不可重复读问题。

保存当前数据的多个版本,有写操作时 也可以快照读。 读写无锁(可能更新丢失问题)
RC 隔离级别下,是每个快照读都会生成并获取最新的 Read View;
RR 隔离级别下,则是同一个事务中的第一个快照读才会创建 Read View, 之后的快照读获取的都是同一个 Read View。

MVCC是利用在每条数据后面加了隐藏的两列(创建版本号和删除版本号),每个事务在开始的时候都会有一个递增的版本号

crud流程
  • 新增:current_version = 1
    insert into user (id,name,age)values(1,“张三”,10);
    在这里插入图片描述

  • 更新:current_version = 2
    update user set age = 11 where id = 1;

    • 更新操作采用delete+add的方式来实现,首先将当前数据标志为删除,然后新增一条新的数据:
      在这里插入图片描述
  • 删除:current_version = 3
    delete from user where id = 1;
    删除操作是直接将数据的删除版本号更新为当前事务的版本号
    在这里插入图片描述

  • 查询操作:
    select * from user where id = 1;
    查询操作为了避免查询到旧数据或已经被其他事务更改过的数据,需要满足如下条件:

    1. 查询时当前事务的版本号需要大于或等于创建版本号
    2. 查询时当前事务的版本号需要小于删除的版本号
      即:create_version <= current_version < delete_version

1.MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read).
2.Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.
原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。
3.串行化由于是会对所涉及到的表加锁,并非行锁,自然也就不存在行的版本控制问题。

分布式事务

  • 事务
    • 原子性(Atomicity)指事务作为整体来执行,要么全部执行,要么全不执行。
    • 一致性(Consistency)指事务应确保数据从一个一致的状态转变为另一个一致的状态。
    • 隔离性(Isolation)指多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
    • 持久性(Durability)指已提交的事务修改数据会被持久保存。

一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,

分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

强一致性与最终一致性

  • 强一致性:本质上是一系列“读”和“写”可见内容的约束,强调的是多副本也不会读到过期数据,
    采用的方法一般是 :操作时隔离不可见+操作可回滚机制
    这就需要隔离性,比如说在2阶段的没有结束,全局事务没有完成的时候,我们可以让数据’不可见’

  • 最终一致性:只要保证最终成功,所以不需要 不可见+回滚 来确保绝对一致,
    采用的办法一般是:用不断重试或人工干预 使失败的事务变成功。

(重要) 强一致性的定义

有两个概念一直没定义清楚,大家的叫法还都不一样,导致学这个一直不明不白,踩了很多坑

也不知道到底该叫什么,有统一标准了告诉我一声

一致性有:多副本的数据读写一致性事务的并发处理一致性

分布式一致性,大多数时候是在讲 多副本之间的数据读写一致性,

至于并发事务读写的一致性(或者叫可见性),大家一般叫做事务隔离级别

多副本的数据读写一致性、CAP一致性

  • CAP中的强一致性是指用户在分布式系统中写完之后,立刻去读,如果能够像本地读写那样,读到最新版本,那么是强一致性。

共识算法:raft、paxos

事务的并发处理一致性、分布式事务一致性、分布式事务隔离级别

  • 分布式事务中的强一致性,是指事务进行的过程中,用户读取的数据始终满足业务约束,目前在实际应用中的方案,都无法做到强一致。

如下:XA,TCC,可靠消息


1. XA 分布式事务协议 (强一致事务)

适用于数据库层面的分布式事务场景(mysql集群间数据同步)

  • XA协议中包含着两个角色:事务协调者TM 和 事务参与者
    协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。
  • 有数据不一致,阻塞等风险
  • XA无法满足高并发场景

XA协议重点要求:可回滚

XA只是协议规范,2PC和3PC是XA的具体实现方式。

1.1 两阶段提交2PC(Two-phase commit protocol)

现阶段几乎所有的分布式事务提交都是通过2PC或者2PC的变种提交

  1. 准备阶段
    协调者TM 向所有 参与者 发送准备请求;
    参与者收到请求后 执行事务,但是不提交,
    然后把事务执行结果发给协调者。
    锁定资源
  2. 提交阶段
    如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;
    否则,协调者发送通知让参与者回滚事务。
    • 回滚,不断重试直到所有参与者都回滚
    • 提交,不断重试直到所有参与者都提交成功。真的不行只能人工介入处理。
      在这里插入图片描述

在这里插入图片描述

  • mysql事务
    在这里插入图片描述
协调者单点故障问题

协调者故障,通过选举得到新协调者

2PC的缺陷

2PC更多强调的是事务的原子性,执行过程中的可见性没有解决,也不去处理多副本间的数据一致性,只是解决了事务的提交问题

  1. 同步阻塞问题:在执行事务的过程当中,所有数据库的资源都被锁定,如果这时候有其他人来访问这些资源,将会被阻塞,这是一个很大的性能问题。
  2. TM单点问题:只要一个TM,一旦TM宕机,那么整个流程无法继续完成。
  3. 数据不一致:如果在执行阶段,参与者脑裂或者其他故障导致没有收到commit请求,部分提交事务,部分未提交,那么数据不一致的问题就产生了。

1.2 三阶段提交 3PC

在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制

事物参与者迟迟没有接到协调者的commit请求,会自动进行本地commit

  1. 准备阶段 CanCommit
    准备阶段 变更成不会直接执行事务,而是询问是否可以执行事务,不能执行直接暂停
    不会一来就直接锁资源
  2. 预提交阶段 PreCommit
    等同于2PC的准备阶段,去执行SQL事务,加入了超时机制 超时自动提交
  3. 提交阶段

超时机制的逻辑:既然CanCommit都能通过,那么超时就不是事务的问题,所以直接提交。

相比2pc优点
  1. CanCommit提前询问 与 超时机制 会缩短阻塞时间,优化了同步阻塞问题和单点问题, 并没有完全避免

阿里AT模式,seata框架

https://seata.io/zh-cn/docs/dev/mode/at-mode.html

2. 可靠消息 (最终一致性事务)

基于消息中间件的两阶段提交

牺牲强一致性换来性能提升,服务解耦

  1. 将分布式事务拆分成本地事务进行处理。利用了各系统本地的事务来实现分布式事务。
  2. 将本地事务和发消息放在了一个本地事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败。(达成本地事务与消息发送的原子性问题)
  3. 通过mq同步消息(达成事务参与方接收消息的可靠性)

2.1 本地消息表

最终一致性事务,适用于一些对时间不敏感的业务。(异步确保一致)

  • 思路:

    1. 本地事务与本地消息绑定,消息放入本地表中业务肯定是执行成功的。不成功的反复重试,直到最终成功
    2. MQ推送分布式事务状态,没有ack的反复推送,直到最终确认
  • 流程

    1. 本地执行事务,根据执行结果 写本地消息表
    2. 后台任务定时去读取本地消息表,筛选出还未成功的消息 再调用对应的服务(确保本地事务成功)
    3. 本地消息表 同步数据给 消息中间件MQ
    4. MQ推送给消费者事务消息,用 MQ的ack消息确认机制 直到分布式事务成功,再变更消息的状态。(确保分布式事务一致)

在这里插入图片描述

2.2 MQ 事务消息

实际上是对本地消息表的一个封装,将本地消息表移动到了 MQ内部
所以支持高并发

RocketMQ 4.3之后的版本正式支持事务消息

RocketMQ 的设计中 broker 与 producer 端的双向通信能力,使得 broker 天生可以作为一个事务协调者存在

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

  • 流程

    1. 生产者发送 【half消息/半消息/预备消息】 给mq,【半消息】不可消费
    2. 生产者方收到半消息成功后,执行本地事务,执行成功后给mq发【成功消息】
    3. mq收到成功消息后,将【半消息】可消费
    4. 消费方收到 生产者的事务成功消息
    5. 消费方执行本地事务,成功则向MQ回应ack,否则将重复接收消息 重试事务
  • 事务回查
    在第2步,生产者执行本地事务时挂掉,mq会问其他生产者来获取事务执行状态。根据回查状态决定是否给消费方消费

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


3. 补偿事务

3.1 TCC (强一致性)

而 TCC 是业务层面的分布式事务
是Try、Confirm、Cancel三种指令的缩写,其逻辑模式类似于XA两阶段提交,但是实现方式是在代码层面来人为实现

  • 第一阶段 Try
    调用 自定义 的 prepare 逻辑。Try 检查及预留业务资源完成提交事务前的检查,并预留资源
    预留资源 会产生可自定义的中间态 :如 金额的冻结状态,

  • 第二阶段 Confirm或Cancel
    Confirm 确定执行业务操作:调用 自定义 的 commit 逻辑。对try阶段预留的资源正式执行。
    Cancel 取消执行业务操作:调用 自定义 的 rollback 逻辑。对try阶段预留的资源释放。进行补偿
    在这里插入图片描述

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


针对每个操作,都要自定义注册一个与其对应的确认和补偿(撤销)操作
在这里插入图片描述

3.2 Sage

SAGA事务,是一种长事务解决方案,
把一个业务流程,分解为多个步骤,每个步骤对应一个本地事务,每个步骤都有一个补偿操作,
Saga首先按流程顺序,执行流程中的每一个步骤(本地事务),如果出现异常,就会按流程顺序反向,执行补偿操作,用于回滚或撤销之前的操作。

分布式服务分为:一阶段正向服务 和 二阶段补偿服务

失败了挨个反向操作上一个的补偿服务 效果=回滚
在这里插入图片描述
无锁,高性能
但中间状态不可控,不保证隔离性

对比

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值