写点什么

【JAVA 秘籍功法篇 - 分布式事务】事务的实现原理

作者:王老狮
  • 2022 年 5 月 04 日
  • 本文字数:3289 字

    阅读完需:约 11 分钟

【JAVA秘籍功法篇-分布式事务】事务的实现原理

事务基本概念

什么是事务?

在我们平常使用 Mysql 等数据库时,经常会遇到事务的提交和回滚等场景。那到底什么是事务呢?


事务是恢复和并发控制的基本单位,事务有四个特性,也是我们常说的 ACID,原子性(Atomicity),一 致性(Consistency),隔离性(Isolation),持久性(Durability)。

事务经典场景

对于银行转账,是我们最常见的事务控制的场景了,比如老王给张三转账 1 万块 ,那整个转账流程为:


  1. 先查询老王账户是否大于 10000

  2. 账户大于 10000,老王账户扣款 10000

  3. 张三账户增加 10000


如果第 2 步骤执行后,系统崩溃掉了。结果如何呢?


问题:A 老王账户被扣了 10000 ,但张三的账户未能加 10000. 此时,老王和张三的金钱总额凭空少了 10000 。那么数据不一致了。


那么我们如何解决呢?


我们希望步骤 1 和步骤 2 能够绑定在一起执行,不可分;并且在步骤 1 和步骤 2 执行的过程中,尽量规避中间状态。即谓事务。


事务在解决上述问题中,提出了以下四种特性

原子性

原子性就是不可拆分的特性,要么全部成功然后提交(commit) ,要么全部失败然后回滚 (rollback)。若开启事务,在上述场景就不会出现了。 MySQL 通过 Redo Log 重做日志实现了原子性,在将执行 SQL 语句时,会先写入 redo log buffer, 再执行 SQL 语句,若 SQL 语句执行出错就会根据 redo log buffer 中的记录来执行回滚操作, 由此拥有原子性。

一致性

一致性指事务将数据库从一种状态转变为下一种一致的状态。比如有一个字段 name 有 唯一索引约束,那么在事务前后都不能有重复的 name 出现违反唯一索引约束,否则回滚。 在上述场景中即金钱总数总是 20000 ,不能凭空增加减少。MySQL 通过 undo Log 实现一致性, 执行 SQL 语句时,会先写入 undo log 再写入 redo log buffer。undo 是逻辑日志,会根据之前 的 SQL 语句进行相应回滚, 比如之前是 insert 那么回滚时会执行一个 delete ,一个 update 会执行 一个相反的 update 。并且除了回滚,undo log 还有一个作用是 MVCC ,当用户读取 一行记录时,若该记录已经被其他事务占用,当前事务可通过 undo 读取之前的行版本信息,实现非锁定读取。并且 undo log 也会产生 redo log ,因为 undo log 也需要持久性的保护。

隔离性

首先介绍如果没有隔离性会发生的 4 种情况


丢失更新


A 事务撤销时,把已经提交的 B 事务的更新数据覆盖了。这种错误可能造成很严重的问 题,通过下面的账户取款转账就可以看出来,MySQL 通过三级封锁协议的第一级解决了丢失更新,事务 T 要修改数据 A 时必须加锁,直到 T 结束才释放锁。


脏读


脏读主要是读取到了其他事务的数据,而其他事务随后发生回滚。MySQL 通过三级封锁 协议的第二级解决了脏读,在一级的基础上,要求读取数据 A 时必须加 S 锁,读取完马上 释放 S 锁。


不可重复读


不可重复读是读取到数据后,随后其他事务对数据发生了修改,无法再次读取。MySQL 通过三级封锁协议的第三级解决了不可重复读。在二级的基础上,要求读取数据 A 时必须 加 S 锁,直到事务结束了才能释放 S 锁。


幻读


幻读是读取到数据后,随后其他事务对数据发生了新增,无法再次读取。在 InnoDB 引擎 Repeatable Read 的隔离级别下,MySQL 通过 Next- Key Lock 以及 MVCC 解决了幻读,事务中 分为当前读以及快照读。

持久性

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据 也不会丢失。具体实现原理就是在事务 commit 之前会将,redo log buffer 中的数据持久化到 硬盘中的 redo logfile ,这样在 commit 的时候,硬盘中已经有了我们修改或新增的数据,由 此做到持久化。

事务原理与锁

锁的问题场景:

多对一问题,多个操作者同时操作一个资源,而资源的状态变化是非原子的(有中间态), 哄抢会导致资源状态混乱


事务的问题场景:

一对多的问题,一个操作者需要绑定操作一系列资源(比如多条 sql),若任何一条操作失败, 都会导致整个操作失去意义;



事务的实现方案

redo log

redo log 叫做重做日志,是用来实现事务的持久性。


该日志文件由两部分组成:重做日志缓冲(redo log buffer) 以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。 当事务提交之后会把所有修改信息都会存到该日志中。


在实际案例中,mysql 为了提升性能不会把每次的数据修改都实时同步到磁盘,而是会先存到 Boffer Pool(缓冲池)里头,把这个当作缓存 来用。然后使用后台线程去做缓冲池和磁盘之间的同步。


redo log 主要用来恢复数据, 用于保障,已提交事务的持久化特性(宕机时,redo log 的信息是全的)

undo log

undo log 叫做回滚日志,用于记录数据被修改前的信息。他正好跟前面所说的重做日志所记录的相反,重做日志记录数据被修改后的信息。


undo log 主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误 时才可以回滚。


mysql 每次写入数据或者修改数据之前都会把修改前的信息记录到 undo log

mysql 锁技术

当多个请求同时来临时,mysql 要控制读读可并行,而写读,写写不能并行


MVCC

MVCC (MultiVersion Concurrency Control) 叫做多版本并发控制。


InnoDB 的 MVCC 是通过在每行记录的后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了 行的过期时间,当然存储的并不是实际的时间值,而是系统版本号。他的主要实现思想是通过数据多版本来做到读写分离。从而实现不加锁读进而做到读写并行。

总结

通过以上技术方案总结


  • 事务的原子性是通过 undo log 来实现的

  • 事务的持久性是通过 redo log 来实现的

  • 事务的隔离性是通过 (读写锁+MVCC)来实现的


事物的一致性则是通过原子性,持久性以及隔离性统一来保证的。

分布式事务概念

分布式事务产生的原因

随着互联网高速发展,事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点 之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用。在这种环境中,我们之前说过数据库的 ACID 四大特性,已经无法满足我们分布式事务。本质上来说,分布式事务就是为了保证不同数据库的数据一致性


如:我们购买王者荣耀的皮肤时,可以使用点券和优惠券,如果不足的可以通过 Q 币在进行补偿。那么我们购买的时候就要扣除我们的优惠券,然后在扣除点券,最后在扣除 Q 币。那么三个操作是在三个不同的服务器的能力,那么之间要通过 RPC 调用才能完成。那么如果我最终 Q 币支付失败了,那整个支付流程都应该是失败的。那我怎么能通知到其他不同库进行业务回滚呢?


分布式中的两个基础理论

在我们做分布式系统中,cap 和 base 理论算是我们经常接触到的了,在这里简单介绍下。,=

CAP 理论

CAP 定理,又被叫作布鲁尔定理。


CAP 指的是:一致性(Consistency) 、可用性(Availability) 、分区容错性(Partition tolerance )。


CAP 定律说的是,在一个分布式系统中,最多只能满足 C 、A 、P 中的两个,不可能三个同时满足。而在分布式系统中,网络无法 100% 可靠,分区其实是一个必然现象。


如果我们选择了 CA 而放弃了 P ,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是 A 又不允许,所以分布式系统理论上 不可能选择 CA 架构,只能选择 CP 或者 AP 架构。


而且,显然任何横向扩展策略都要依赖于数据分区。因此,设计人员必须在一致性与可用性之间做出选择。

BASE 理论

往往在分布式系统中无法实现完全一致性,于是有了 BASE 理论,它是对 CAP 定律的进一步扩充


BASE 指的是:


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

  2. Soft state (软状态) : 允许系统中存在中间状态,这个状态不影响系统可用性

  3. Eventually consistent (最终一致性) : 经过一段时间后,所有节点数据都将会达到一致


BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果


BASE 理论核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性


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

发布于: 刚刚阅读数: 2
用户头像

王老狮

关注

抛弃过往的经验,回到问题的本质! 2018.03.27 加入

还未添加个人简介

评论

发布
暂无评论
【JAVA秘籍功法篇-分布式事务】事务的实现原理_分布式事务_王老狮_InfoQ写作社区