• 【高并发基础】理解 MVCC 及提炼实现思想


    1. 前言

    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. 提出问题

    如何控制当前事务读不到其他事务 未提交 的数据

    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
    
    • 1
    • 2
    • 3

    4.1 不读未提交的数据

    4.1.1 没有并发

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

    trx_id >= Read View. max_trx_id  // max_trx_id 表示下一个事务颁发的id, 所以取等号时,该记录也不属于自己的事务
    
    • 1

    则说明该日志发生在建立 Read View 之后,并且生成该日志的事务是在当前事务之后开启。
    至此,我们能够得到一个信息:该日志发生在当前事务开启之后,直接舍弃

    trx_id < Read View. min_trx_id
    
    • 1

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


    4.1.2 有并发

    新引入两个参数

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

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

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

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


    5. MVCC DML 会生成新的 Read View 吗?

    并不会,DML语句操作语句交给锁处理了,MVCC只是控制读取的数据的版本。
    那么DML跟Read View无关吗,当然也不是,使用 creator_trx_id 登记自己操作了的数据。
    如果creator_trx_id == 日志中的trx_id,则是自己操作的数据,直接读取即可

    6. MySQL RC 及 RR 使用 MVCC 的时机

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

    • RR
      RR 的隔离级别比 RC 高,其中隔离性的提高本质上就是调整了 Read View 创建的时机
      第一个查询语句生成 Read View,后续的所有查询都 复用这个 Read View,所以每次读取的值,都来源于同一个版本。

    7. 提炼 MVCC 的思想

    MVCC 用 ReadView 的创建实现事务隔离,同时又尽最大努力去读最新的数据。建立 Read View 时,登记一刹那的事务并发情况。读取具体数据库记录的时候,有日志文件和 Read View共同决策是否信任此日志的数据。回顾以下模型:

    在这里插入图片描述

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

    8. 后记

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

  • 相关阅读:
    js 对象循环遍历
    2022搜狐校园NLP算法大赛情感分析第一名方案理解和复现
    LeetCode 第2题:两数相加(Python3解法)
    mysql [ERROR] mysql unknown option ‘-a‘
    将目录下的所有pdf文件都转换为对应名字的png图片
    ESP32 Arduino 引入LVGL 碰到的一些问题
    python通过socket 搭建极简web服务器
    C#virtual关键
    数据分析--matplotlib绘图
    数据结构--单链表
  • 原文地址:https://blog.csdn.net/chenghan_yang/article/details/128172873