【高并发基础】理解MVCC及提炼实现思想-创新互联

文章目录
    • 1. 前言
    • 2. MVCC 概念
      • 2.1 MVCC 版本链
      • 2.2 MVCC trx_id
      • 2.3 MVCC Read View
    • 3. 提出问题
    • 4. 解决问题
      • 4.1 不读未提交的数据
        • 4.1.1 一般的并发情况
        • 4.1.2 特殊的并发情况
        • 4.1.3 剩下的并发情况
      • 4.2 如果自己修改了数据,要第一时间读到
    • 5. MySQL RC 使用 MVCC
      • 5.1 MVCC DML 会生成新的 Read View 吗?
      • 5.2 MySQL RC 建立 Read View 的时机
    • 6. MySQL RR 使用 MVCC
      • 6.1 MySQL RR 建立 Read View 的时机
    • 7. 提炼 MVCC 的思想
    • 8. 后记

成都创新互联公司于2013年开始,是专业互联网技术服务公司,拥有项目成都网站设计、做网站网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元泾县做网站,已为上家服务,为泾县各地企业和个人服务,联系电话:189820811081. 前言

MVCC 在 MySQL、Oracle、PostgreSQL 都有应用,用于实现事务的隔离特性。现在结合 《MySQL是怎样运行的》的内容理解、归纳、整理下MVCC的实现及思想。

2. MVCC 概念

Multiversion Concurrency Control 对版本并发控制。
对于同一行数据,会根据不同事务的DML操作参生不同的版本,让不同事务各自维护自己能看到的版本从而做到事务隔离。

2.1 MVCC 版本链

每次操作数据库都会生成日志,那么就可以把同一条记录的多次操作记录按时间顺序链接起来。
在这里插入图片描述

以上图片参考博客

2.2 MVCC trx_id

按事务开启的时间顺序,为事务颁发一个Id,从而维护“版本”。是讨论MVCC实现的基础。

2.3 MVCC Read View

光有日志记录还不够,每个事务应该要维护自己的 “视野范围”。也就是当前事务到底能看到什么版本的数据,建立 Read View,并与版本链协作,就能约束事务的视野,从而实现隔离。
Read View 包含:

  1. m_ids
  2. min_trx_id
  3. max_trx_id
  4. creator_trx_id

Read View 里面有多个属性,他们是分别用于解决不同问题的。如果一上来就把四个都搞懂,容易晕。

3. 提出问题

这个事务隔离方案需要回答以下问题:

  • 如何控制当前事务读不到其他事务 未提交 的数据
  • 如果自己事务修改了数据,怎么第一时间读到

回答以上问题后,也顺带把MySQLRCRR使用MVCC的原理给理解了

4. 解决问题

我们把日志的 trx_id 与 区间 [min_trx_id, max_trx_id ] 的命中关系罗列出来,用于后续讨论问题

trx_id >= Read View. max_trx_id
Read View. max_trx_id  >trx_id  >=  Read View. min_trx_id
trx_id< Read View. min_trx_id

值得一提的是,

trx_id == Read View. creator_trx_id

不在区间讨论范围,属于前置判断(这个条件满足了,就不看区间命中情况了)

4.1 不读未提交的数据 4.1.1 一般的并发情况

新引入以下参数:

  • max_trx_id:这个属性容易搞混,它表示系统应该分配给下一个事务的食物Id
    • 即若 creator_trx_id = 3,max_trx_id 一定 >3

事务生成了 Read View 之后,对数据行进行读取,发现日志中有

trx_id >= Read View. max_trx_id

则说明该日志发生在建立 Read View 之后,并且生成该日志的事务是在当前事务之后开启。
至此,我们能够得到一个信息:该日志发生在当前事务开启之后,可能是还未提交的事务
那么,争取不读未提交的事务,只用做一件事:忽略该日志


4.1.2 特殊的并发情况

新引入两个参数

  • min_trx_id: 当前所有事务中,活跃的(未提交的)事务中 trx_id 最小的一个
  • m_ids: 当前所有事务中,活跃的(未提交的)事务列表

事务生成了 Read View 之后,对数据行进行读取,发现日志中有

Read View. max_trx_id  >trx_id  >=  Read View. min_trx_id

则说明该日志发生在建立 Read View 之后,并且生成该日志的事务是在当前事务之后开启。
对比上文的"一般的情况",max_trx_id指系统下一个要建立的事务Id,若存在以下关系:

Read View. max_trx_id  >trx_id

说明该日志的事务跟建立 Read View 的时机挨得很近,我们还是可以考虑一下这条日志。具体怎么考虑呢?
m_ids 在 Read View 中负责记录建立 Read View 那一刻的 活跃事务。
如果日志中的 trx_id 不在活跃事务列表,侧面说明该日志的事务已经提交,则可以读取它。


4.1.3 剩下的并发情况
trx_id< Read View. min_trx_id

这个比较简单,直接读即可。由于较新的日志一定会置顶,读到 trx_id< Read View. min_trx_id 立马返回数据即可。


4.2 如果自己修改了数据,要第一时间读到

引入以下参数

  • creator_trx_id: Read View 中事务的DML操作会触发建立 trx_id (事务id)
trx_id == Read View. creator_trx_id

该日志是当前事务的最新语句创建的,直接读取即可。该判断放在了区间命中讨论之前,所以一定会先读到自己更新的数据。
如果开启一个事务,该事务一直没有DML操作,creator_trx_id = 0,即永远不会出现

trx_id == Read View. creator_trx_id
5. MySQL RC 使用 MVCC

MySQL 会对每个查询语句生成 Read View。

5.1 MVCC DML 会生成新的 Read View 吗?

并不会,DML语句操作语句交给锁处理了,MVCC只是控制读取的数据的版本。
那么DML跟Read View无关吗,当然也不是,上文交代,使用 creator_trx_id 登记自己操作了的数据。

5.2 MySQL RC 建立 Read View 的时机

每个读取操作都会建立一个新的 Read View, 所以存在不可重复读的并发隐患。

6. MySQL RR 使用 MVCC

RR 的隔离级别比 RC 高,其中隔离性的提高本质上就是调整了 Read View 创建的时机

6.1 MySQL RR 建立 Read View 的时机

第一个查询语句生成 Read View,后续的所有查询都 复用这个 Read View,所以每次读取的值,都来源于同一个版本。

7. 提炼 MVCC 的思想

MVCC 在保持隔离性的前提下,尽大努力去读最新的数据。它不会立即判断数据是未提交的,而是记录下建立 Read View 那一刹那的事务并发情况,交由一套算法去甄别。

  • 怀疑日志是未提交的数据

    • 自己DML操作的数据
      • 由 creator_trx_id 跟进记录并读取
    • 其他事务DML操作的数据
      • 由 trx_id 与 区间 [min_trx_id, max_trx_id ] 的命中关系确认为已提交数据则读取
  • 确认日志是已提交的数据

    • 读最新的版本

上文说的日志,是因为日志承载的是一个思想,MySQL是用 undo log支撑MVCC的,而PostgreSQl则不是。

8. 后记

早期写的 InnoDB 如何避免脏读和不可重复读,是不严谨的地方,现在纠正过来,希望持续学习,不断进步。
MVCC 给我的启示是,我们可以尝试用区间命中的思想去分解问题,当命中关系被完全覆盖,我们可以认为问题被分解完成。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前题目:【高并发基础】理解MVCC及提炼实现思想-创新互联
本文链接:http://myzitong.com/article/cdsseg.html