一、并发控制

 
因为并发情况下有可能出现不同线程对同一资源进行变动,所以必须要对并发进行控制以保证数据的同一与安全。
 
可以参考CPython解释器中的GIL全局解释器锁,所以说python中没有真正的多线程,多线程任意时刻只有一个程序能申请到GIL操作CPU。

 

1.2 Innodb中的并发控制

 

锁(lock)
数据多版本(multi versioning)

 

1.2.1 锁

 

  • 使用普通锁来保证数据的一致性:
     
    操作数据前实行互斥,即当前程序曹锁数据时,不允许其他并发任务操作该数据,进入排队等待
    操作完成后释放锁
     

  • 普通锁问题:
    锁定粒度大,容易出现死锁
    简单粗暴,没有并行“读任务”,本质上是串行执行任务。

  • 正对上述问题,有了共享锁及排他锁

  1. 共享锁(share locks 称为S锁)读取数据时加S锁
    共享锁之间不互斥,简记为:读读可以并行

  2. 排他锁(exclusive locks 称为X锁)修改数据时加X锁
    排他锁与任何锁互斥,简记为:写读,写写不可以并行

上述中可以了解到,只要修改数据时加了排他锁, 其它操作同一数据的并行线程都进入了排队等待释放锁。且写的数据没有完成提交的话,其它任务是没法去读取数据的,也阻塞了

 

1.2.2 数据多版本(某种意义的读写分离)

 

  • 作为一种提高并发的方式:原理
  1. 写任务发生时,将数据克隆一份,以版本号区分;

  2. 写任务操作新克隆的数据,直至提交;

  3. 并发读任务可以继续读取旧版本的数据,不至于阻塞;

  • 如上图:
  1. 最开始数据的版本是V0;

  2. T1时刻发起了一个写任务,这是把数据clone了一份,进行修改,版本变为V1,但任务还未完成;

  3. T2时刻并发了一个读任务,依然可以读V0版本的数据;

  4. T3时刻又并发了一个读任务,依然不会阻塞;

可以看到,数据多版本,通过“读取旧版本数据”能够极大提高任务的并发度。

总结:

  • 普通锁,本质是串行执行

  • 读写锁,可以实现读读并发
  • 数据多版本,可以实现读写并发

 

二、Innodb redo/undo 日志、回滚段 (rollback segment) 操作,实现上述思路

 

  • ACID:
    原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

 

2.1 redo日志

 

数据库事务提交后,必须将更新后的数据刷到磁盘上,以保证ACID特性。磁盘随机写性能较低,如果每次都刷盘,会极大影响数据库的吞吐量。

优化方式为:将修改行为先写到redo日志里(此时变成了顺序写),再定期将数据刷到磁盘上,这样能极大提高性能。

假如某一时刻,数据库崩溃,还没来得及刷盘的数据,在数据库重启后,会重做redo日志里的内容,以保证已提交事务对数据产生的影响都刷到磁盘上。

一句话,redo日志用于保障,已提交事务的ACID特性。

 

2.2 undo日志

 

数据库事务未提交时,会将事务修改数据的镜像(即修改前的旧版本)存放到undo日志里,当事务回滚时,或者数据库奔溃时,可以利用undo日志,即旧版本数据,撤销未提交事务对数据库产生的影响。

对于insert操作,undo日志记录新数据的PK(ROW_ID),回滚时直接删除;

对于delete/update操作,undo日志记录旧数据row,回滚时直接恢复;

他们分别存放在不同的buffer里。

一句话,undo日志用于保障,未提交事务不会对数据库的ACID特性产生影响。

 

2.3 回滚段

 

存储undo日志的地方,是回滚段。

undo日志和回滚段和InnoDB的MVCC密切相关

建议看完MVCC原理再看下面:MVCC原理
直接看也行

举例:
create table tb(
id int auto_increment primary key,
name cahr(32));

插入三条数据
1, shenjian

2, zhangsan

3, lisi

此时没有事务未提交,故回滚段是空的。

接着启动了一个事务:

start trx;

delete (1, shenjian);

update set(3, lisi) to (3, xxx);

insert (4, wangwu);

并且事务处于未提交的状态。

可以看到:

(1)被删除前的(1, shenjian)作为旧版本数据,进入了回滚段;

(2)被修改前的(3, lisi)作为旧版本数据,进入了回滚段;

(3)被插入的数据,PK(4)进入了回滚段;

接下来,假如事务rollback,此时可以通过回滚段里的undo日志回滚。

假设事务提交,回滚段里的undo日志可以删除。

可以看到:

(1)被删除的旧数据恢复了;

(2)被修改的旧数据也恢复了;

(3)被插入的数据,删除了;

事务回滚成功,一切如故。

 

三、innodb 是基于MVCC(多版本并发控制)的存储引擎

 
InnoDB是高并发互联网场景最为推荐的存储引擎,根本原因,就是其多版本并发控制(Multi Version Concurrency Control, MVCC)。行锁,并发,事务回滚等多种特性都和MVCC相关。

MVCC就是通过“读取旧版本数据”来降低并发事务的锁冲突,提高任务的并发度。

旧数据存储的地方:
(1)旧版本数据存储在回滚段里;

(2)对MySQL和InnoDB原有架构体系冲击不大;

InnoDB的内核,会对所有row数据增加三个内部属性:

(1)DB_TRX_ID,6字节,记录每一行最近一次修改它的事务ID;

(2)DB_ROLL_PTR,7字节,记录指向回滚段undo日志的指针;

(3)DB_ROW_ID,6字节,单调递增的行ID;

回滚段里的数据,其实是历史数据的快照(snapshot),这些数据是不会被修改,select可以肆无忌惮的并发读取他们。

快照读(Snapshot Read),这种一致性不加锁的读(Consistent Nonlocking Read),就是InnoDB并发如此之高的核心原因之一。

这里的一致性是指,事务读取到的数据,要么是事务开始前就已经存在的数据(当然,是其他已提交事务产生的),要么是事务自身插入或者修改的数据。

什么样的select是快照读?

除非显示加锁,普通的select语句都是快照读,例如:

select * from t where id>2;

这里的显示加锁,非快照读是指:

select * from t where id>2 lock in share mode;

select * from t where id>2 for update;

总结

(1)常见并发控制保证数据一致性的方法有锁,数据多版本;

(2)普通锁串行,读写锁读读并行,数据多版本读写并行;

(3)redo日志保证已提交事务的ACID特性,设计思路是,通过顺序写替代随机写,提高并发;

(4)undo日志用来回滚未提交的事务,它存储在回滚段里;

(5)InnoDB是基于MVCC的存储引擎,它利用了存储在回滚段里的undo日志,即数据的旧版本,提高并发;

(6)InnoDB之所以并发高,快照读不加锁;

(7)InnoDB所有普通select都是快照读;

Innodb 实现高并发、redo/undo MVCC原理的更多相关文章

  1. MySQL InnoDB 实现高并发原理

    MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...

  2. InnoDB高并发原理

    一.并发控制 为啥要进行并发控制? 并发的任务对同一个临界资源进行操作,如果不采取措施,可能导致不一致,故必须进行并发控制(Concurrency Control). 技术上,通常如何进行并发控制? ...

  3. (转载)java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  4. 《Netty Zookeeper Redis 高并发实战》 图书简介

    <Netty Zookeeper Redis 高并发实战> 图书简介 本书为 高并发社群 -- 疯狂创客圈 倾力编著, 高度剖析底层原理,深度解读面试难题 疯狂创客圈 Java 高并发[ ...

  5. 尼恩 Java高并发三部曲 [官方]

    高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三部曲 > 面试必备 + 大厂必备 + 涨薪 ...

  6. SpringCloud、Nginx高并发核心编程 【2020年11月新书 】

    文章太长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典极品 : 三大本< Java 高并发 三部曲 > 面试 + 大厂 + 涨薪必备 疯狂创客圈 经 ...

  7. InnoDB事务日志(redo log 和 undo log)详解

    数据库通常借助日志来实现事务,常见的有undo log.redo log,undo/redo log都能保证事务特性,undolog实现事务原子性,redolog实现事务的持久性. 为了最大程度避免数 ...

  8. Mysql 中的MVCC原理,undo日志的依赖

    一. MVCC 原理了解   原文点击:MVCC原理浅析 读锁: 也叫共享锁.S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的 ...

  9. MVCC原理 4步 什么是MVCC、事务ACID、事物隔离级别、Innodb存储引擎是如何实现MVCC的

    MVCC是来处理并发的问题,提高并发的访问效率,读不阻塞写.事物A 原子性C 一致性I 隔离性D 持久性高并发的场景下的问题脏读不可重复读幻读事物隔离级别RU读未提交 脏读/不可重复读/幻读 .不适用 ...

随机推荐

  1. JavaScript -- 时光流逝(十二):DOM -- Element 对象

    JavaScript -- 知识点回顾篇(十二):DOM -- Element 对象 (1) element.accessKey: 设置或返回accesskey一个元素,使用 Alt + 指定快捷键 ...

  2. LeetCode算法题-Guess Number Higher or Lower(Java实现)

    这是悦乐书的第211次更新,第224篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第79题(顺位题号是374).我们正在玩数字游戏. 游戏如下:我从1到n中选择一个数字. ...

  3. Linux for Python教程01

    目录 1. Linux和操作系统 1.1. 什么是操作系统 1.2. 现有操作系统 1.3. Linux用户目录 1.4. Linux文件权限 2. Linux命令 2.1 文件管理相关 (1).ls ...

  4. #010 全年级C语言开始统一刷题了,能否坚持下去?

    不知道这是咋回事吧,这个系统挺不好使得,出现了一个又一个的问题. 使用过程中做题的那个系统自己就崩了,刷新后那道题得了零分. 前面的几道题难度系数也不小,对于我这个新手来说,但是这个系统太坑了.他明码 ...

  5. 我使用的Bem的习惯

    在基于BEM命名思想的基础上,我整理一些实用的点: BEM,B即block(块),E即element(元素),M即modifier(修饰符) 块:最顶层,可包含块和元素 元素:被块包含,通常为最终被包 ...

  6. mysql 更新条件为查询出的结果

    UPDATE category c INNER JOIN ( SELECT b.category_id FROM category a, (SELECT * FROM category WHERE d ...

  7. BZOJ2521:[SHOI2010]最小生成树(最小割)

    Description Secsa最近对最小生成树问题特别感兴趣.他已经知道如果要去求出一个n个点.m条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法.另外,他还知道,某一个图可 ...

  8. ArrayList中ConcurrentModificationException

    java中两种基本的集合结构ArrayList和LinkedList底层有两种不同的存储方式实现,ArrayList为数组实现,属于顺序存储,LinkedList为链表实现,属于链式存储,在对Arra ...

  9. X86-64寄存器和栈帧--牛掰降解汇编函数寄存器相关操作

    X86-64寄存器和栈帧 概要 说到x86-64,总不免要说说AMD的牛逼,x86-64是x86系列中集大成者,继承了向后兼容的优良传统,最早由AMD公司提出,代号AMD64:正是由于能向后兼容,AM ...

  10. Jmeter自定义Java请求,继承AbstractJavaSamplerClient

    首先,使用Eclipse新建一个项目,然后从Jmeter的lib/ext目录下中拷贝ApacheJMeter_java.jar和ApacheJMeter_core.jar两个文件,然后引入这两个JAR ...