文章目录
事务
原子性(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的方式来实现,首先将当前数据标志为删除,然后新增一条新的数据:
- 更新操作采用delete+add的方式来实现,首先将当前数据标志为删除,然后新增一条新的数据:
-
删除:current_version = 3
delete from user where id = 1;
删除操作是直接将数据的删除版本号更新为当前事务的版本号
-
查询操作:
select * from user where id = 1;
查询操作为了避免查询到旧数据或已经被其他事务更改过的数据,需要满足如下条件:- 查询时当前事务的版本号需要大于或等于创建版本号
- 查询时当前事务的版本号需要小于删除的版本号
即: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的变种提交
- 准备阶段
协调者TM 向所有 参与者 发送准备请求;
参与者收到请求后 执行事务,但是不提交,
然后把事务执行结果发给协调者。
锁定资源 - 提交阶段
如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;
否则,协调者发送通知让参与者回滚事务。- 回滚,不断重试直到所有参与者都回滚
- 提交,不断重试直到所有参与者都提交成功。真的不行只能人工介入处理。
- mysql事务
协调者单点故障问题
协调者故障,通过选举得到新协调者
2PC的缺陷
2PC更多强调的是事务的原子性,执行过程中的可见性没有解决,也不去处理多副本间的数据一致性,只是解决了事务的提交问题
- 同步阻塞问题:在执行事务的过程当中,所有数据库的资源都被锁定,如果这时候有其他人来访问这些资源,将会被阻塞,这是一个很大的性能问题。
- TM单点问题:只要一个TM,一旦TM宕机,那么整个流程无法继续完成。
- 数据不一致:如果在执行阶段,参与者脑裂或者其他故障导致没有收到commit请求,部分提交事务,部分未提交,那么数据不一致的问题就产生了。
1.2 三阶段提交 3PC
在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制
事物参与者迟迟没有接到协调者的commit请求,会自动进行本地commit
- 准备阶段 CanCommit
准备阶段 变更成不会直接执行事务,而是询问是否可以执行事务,不能执行直接暂停
不会一来就直接锁资源 - 预提交阶段 PreCommit
等同于2PC的准备阶段,去执行SQL事务,加入了超时机制 超时自动提交 - 提交阶段
超时机制的逻辑:既然CanCommit都能通过,那么超时就不是事务的问题,所以直接提交。
相比2pc优点
- CanCommit提前询问 与 超时机制 会缩短阻塞时间,优化了同步阻塞问题和单点问题, 并没有完全避免
阿里AT模式,seata框架
https://seata.io/zh-cn/docs/dev/mode/at-mode.html
2. 可靠消息 (最终一致性事务)
基于消息中间件的两阶段提交
牺牲强一致性换来性能提升,服务解耦
- 将分布式事务拆分成本地事务进行处理。利用了各系统本地的事务来实现分布式事务。
- 将本地事务和发消息放在了一个本地事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败。(达成本地事务与消息发送的原子性问题)
- 通过mq同步消息(达成事务参与方接收消息的可靠性)
2.1 本地消息表
最终一致性事务,适用于一些对时间不敏感的业务。(异步确保一致)
-
思路:
- 本地事务与本地消息绑定,消息放入本地表中业务肯定是执行成功的。不成功的反复重试,直到最终成功
- MQ推送分布式事务状态,没有ack的反复推送,直到最终确认
-
流程
- 本地执行事务,根据执行结果 写本地消息表
- 后台任务定时去读取本地消息表,筛选出还未成功的消息 再调用对应的服务(确保本地事务成功)
- 本地消息表 同步数据给 消息中间件MQ
- MQ推送给消费者事务消息,用 MQ的ack消息确认机制 直到分布式事务成功,再变更消息的状态。(确保分布式事务一致)
2.2 MQ 事务消息
实际上是对本地消息表的一个封装,将本地消息表移动到了 MQ内部
所以支持高并发
RocketMQ 4.3之后的版本正式支持事务消息
RocketMQ 的设计中 broker 与 producer 端的双向通信能力,使得 broker 天生可以作为一个事务协调者存在
利用消息中间件来异步完成事务的后一半更新,实现系统的最终一致性。这个方式避免了像XA协议那样的性能问题。
-
流程
- 生产者发送 【half消息/半消息/预备消息】 给mq,【半消息】不可消费
- 生产者方收到半消息成功后,执行本地事务,执行成功后给mq发【成功消息】
- mq收到成功消息后,将【半消息】可消费
- 消费方收到 生产者的事务成功消息
- 消费方执行本地事务,成功则向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首先按流程顺序,执行流程中的每一个步骤(本地事务),如果出现异常,就会按流程顺序反向,执行补偿操作,用于回滚或撤销之前的操作。
分布式服务分为:一阶段正向服务 和 二阶段补偿服务
失败了挨个反向操作上一个的补偿服务 效果=回滚
无锁,高性能
但中间状态不可控,不保证隔离性