美文网首页
InnoDB的并发控制(转)

InnoDB的并发控制(转)

作者: 阿猫阿狗Hakuna | 来源:发表于2018-08-31 10:55 被阅读7次

    一.并发控制

    为什么要进行并发控制?

    并发的任务对同一个临界资源进行操作,如果不采取措施,可能导致不一致,故必须进行并发控制。

    技术上,通常如何进行并发控制?

    通过并发控制保证数据一致性的常见手段有:
    -锁
    -数据多版本

    二.锁

    如何使用普通锁保证一致性?

    (1)操作数据前 ,锁住,实施互斥,不允许其他并发任务操作
    (2)操作完成后,释放锁,让其他任务执行

    存在的问题?

    太过粗暴,读任务也无法并行,任务执行过程本质上是串行的

    于是出现了共享锁与排他锁

    (1)共享锁(Share Locks,记为S锁),读数据时加S锁
    (2)排他锁(eXclusive Locks,记为X锁),修改数据时加X锁

    共享锁与排他锁的玩法

    (1)共享锁之间不互斥,读读可以并行
    (2)排它锁与任何锁互斥,写读,写写不可并行
    写数据的任务没有完成,数据不能被其他任务读取,这对并发有较大影响

    有没有可能进一步提高并发?

    数据多版本

    三.数据多版本

    数据多版本是一种能进一步提高并发的方法,核心原理是:
    (1)写任务发生时,将数据克隆一份,以版本号区分;
    (2)写任务操作克隆的数据,直至提交;
    (3)并发读任务可以继续读取旧版本数据,不至于阻塞;


    image.png

    提高并发的演进思路:
    (1)普通锁,串行执行
    (2)读写锁,读读并发
    (3)数据多版本,读写并发

    对应到InnoDB上,是怎么玩的?

    四.redo,undo,回滚段

    为什么要有redo日志?

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

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

    这里的设计方法:随机写优化为顺序写

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

    一句话,redo日志用于保障已提交事务的ACID特性。
    为什么要有undo日志?

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

    一句话,undo日志用于保证,未提交事务不会对数据库的ACID产生影响。
    什么是回滚段?

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

    undo日志和回滚段和InnoDB的MVCC密切相关,这里举个例子展开说明一下。

    表:

    t(id PK,name)

    数据为:
    1, shenjian
    2, zhangsan
    3, lisi


    ![微信图片_20180831104514.jpg](https://img.haomeiwen.com/i2818100/5e281b197986263f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    此时没有事务未提交,回滚段为空

    接着启动了一个事务:
    start trx;
    delete(1, shenjian);
    update set(3,lisi) to (3,xxx);
    insert(4,wangwu);
    并且事务处于未提交状态


    微信图片_20180831104514.jpg

    可以看到:
    (1)被删除前的(1, shenjian)作为旧版本数据,进入了回滚段;
    (2)被修改前的(3, lisi)作为旧版本数据,进入了回滚段;
    (3)被插入的数据,PK(4)进入了回滚段;

    接下来,加入事务rollback,可以通过回滚段里的undo日志回滚


    微信图片_20180831104724.jpg

    可以看到:
    (1)被删除的旧数据恢复了;
    (2)被修改的旧数据也恢复了;
    (3)被插入的数据,删除了;



    事务回滚成功,一切如故

    四.InnoDB是基于多版本并发控制的存储引擎

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

    核心问题:
    旧版本数据存储在哪里?
    存储旧版本数据,对Mysql和InnoDB原有架构是否有巨大冲击?

    (1)旧版本数据存储在回滚段里;
    (2)冲击不大

    InnoDB的内核,会对所有row数据增加三个内部属性:
    (1)DB_TRX_ID,6字节,记录每一行最近一次修改它的事务ID;
    (2)DB_ROLL_PTR,7字节,记录指向回滚段undo日志的指针;
    (3)DB_ROW_ID,6字节,单调递增的行ID;

    InnoDB为何能做到这么高的并发?

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

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

    这里的一致性指的是:事务读取到的数据,要么是数据开始前就已经存在的数据,要么是事务自身插入或者修改的数据。

    什么样的select是快照读?

    什么样的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的并发控制(转)

          本文链接:https://www.haomeiwen.com/subject/glfswftx.html