zoukankan      html  css  js  c++  java
  • Innodb 实现高并发、redo/undo MVCC原理

    http://www.cnblogs.com/shiqi17/p/9787940.html
    一、并发控制

     
    因为并发情况下有可能出现不同线程对同一资源进行变动,所以必须要对并发进行控制以保证数据的同一与安全。
     
    可以参考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都是快照读;

    人生还有意义。那一定是还在找存在的理由
  • 相关阅读:
    《DSP using MATLAB》Problem 6.17
    一些老物件
    《DSP using MATLAB》Problem 6.16
    《DSP using MATLAB》Problem 6.15
    《DSP using MATLAB》Problem 6.14
    《DSP using MATLAB》Problem 6.13
    《DSP using MATLAB》Problem 6.12
    《DSP using MATLAB》Problem 6.11
    P1414 又是毕业季II
    Trie树
  • 原文地址:https://www.cnblogs.com/fengff/p/10827249.html
Copyright © 2011-2022 走看看