MySQL 读书笔记 (二) InnoDB初探

一、什么是InnoDB

从MySQL 5.5 开始 InnoDB 就作为了默认表存储引擎,完整的支持了MySQL的ACID事物。是OLTP应用中核心表的首选存储引擎。

其特点如下:
支持行锁、支持MVCC、支持外健、提供一致性非锁定读(不可重复读的现象就是它的锅,READ COMMIT级别下会默认读取最新的一次快照)。

二、体系架构

先来看一张架构图感受下:

MySQL 读书笔记 (二) InnoDB初探_第1张图片

如图所示,其主要分为三个部分,后台线程、内存池(由多个内存块组成)、磁盘文件。后台线程负责刷新内存池中的数据,保证内存池中缓存的数据是最新的。并将修改的数据文件刷新到磁盘文件,同时保证在数据库发送异常的时候能恢复到正常状态。

下面就来详细说下各功能模块:
1、后台线程
InnoDB 存储引擎是多线程的模型,所以由多个不同的线程处理任务。

  • Master Thread
    核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘并保证一致性,包括脏页的刷新、合并插入缓冲、UNDO页回收。

  • IO Thread
    InnoDB 大量的使用了AIO来处理请求,IOThread主要负责这些请求IO 的回调处理。由 read、 write 、insert buffer 、log io Thread组成。

  • Purge Thread
    事物提交后,undo log不需要了,但不能马上被回收(比如要保证一致性非锁定读,用以来获取历史版本)。所以需要一个独立的线程进行回收

  • Page Cleaner Thread
    InnoDB 1.2版本后将脏页的刷新单独拎了出来,用来减轻Master Thread 压力。

2.InnoDB存储引擎内存池

MySQL 读书笔记 (二) InnoDB初探_第2张图片

  • 缓冲池
    innoDB 存储引擎是基于磁盘存储的,但由于cpu速度与磁盘速度的鸿沟,所以需要一个内存缓冲技术来提高整体性能。而缓冲池说白了就是一块内存区域,缓冲池中页大小默认为16k.(1.0.x版本后主持压缩页功能,可压缩为1k\2k\4k\8k)

缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲、自适应哈希索引、InnoDB 存储的锁信息、数据字典信息(允许有多个缓冲池,页根据哈希值平均分配到不同的缓冲池中)

  • 读操作
    在数据库进行读取页的时候,首先将磁盘读取到的页放入缓冲池,这个过程称为 页 FIX 在缓冲池中。下次在读取相同页时,首先判断是否在缓冲池,若在则称为该页缓存池中命中,不再就读取磁盘上的页。

  • 写操作
    对于数据修改,首先修改在缓冲池中的页,然后再以一定频率刷新到磁盘。并不是每次页改变就刷新到磁盘,而是通过Checkpoint的机制刷新回磁盘。

3 缓存池管理

使用LRU List 、Free List 和Flush List 来管理缓冲池。

  • LRU List :

    优化过的LRU 算法,增加了midpoint位置,新访问的页不是放在LRU列表首部,而是放在midpoint位置。读取的数据放在这个列表中

  • Free List

    系统刚启动时,LRU列表是空的(LRU列表是用来管理已读的页)。这时候的页都放在Free List列表中。当需要从缓存池中分页时,首先从Free 列表中查找是否有可用的空闲页,若有则将该页从Free列表删除,放入LRU列表中。否则根据LRU算法淘汰LRU列表末尾页,将该内存空间分配给新页。

  • Flush List
    LRU 列表中的页被修改后,称该页为脏页,就是缓存池中的页和磁盘上的页数据产生了不一致。这时候就通过Checkpoint机制将脏页刷新回磁盘.而Flush 列表中的页就是脏页列表,注意脏页即存在LRU列表中,也存在Flush列表中。LRU列表来管理缓冲池中页的可用性,Flush列表用来管理将页刷新回磁盘。

  • 重做缓冲日志
    先说下概念,重做日志缓冲(redo log buffer) 就是通常是物理日志,记录页的修改。事物的原子性、和持久性就是它来保证的,这里先不展开絮叨。

    在InnoDB存储引擎内存区域除了缓存池外,还包含了重做日志缓冲(redo log buffer)。其实就是将重做日志信息先放到这个缓冲区,然后按照一定频率刷新到重做日志文件。

    说到刷新到重做日志文件刷新策略:

    • Master Thread 每一秒将重做日志缓冲刷新到重做日志文件

    • 每个事物提交时会将重做日志缓冲刷新到重做日志文件

    • 当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件

  • Checkpoint技术
    一直再说脏页的刷新使用的是Checkpoint技术,下面就来了解下这个到底是什么样的机制。

    在InnoDB存储引擎内部有以下两种Checkpoint:

    • Sharp Checkpoint
      其是发生在数据库关闭时将所有的脏页都刷新回磁盘,是默认的工作方式

    • Fuzzy Checkpoint
      只刷新一部分脏页,包含几种情况:
      1) Master Thread Checkpoint 大概以每秒或每十秒的速度异步刷新
      2) FLUS_LRU_LIST Checkpoint LRU大概要保证有差不多100个空闲页可以使用,如果小于此,就讲其中的脏页刷回磁盘
      3) Async/Sync FLush Checkpoint 重做日志文件不可用时,需要强制将一些脏页刷新回磁盘。
      4) Dirty Page too much Checkpoint 脏页数目太多导致存储引擎强制Checkpoint,目的还是保证缓冲池有足够的可用页。(默认75%)

  • Master Thread
    说了后台线程和内存中的一些核心概念,现在再回到后台线程Master Thread上,因为它实在是太重要了,不得不着重说一下。
    Master Thread 具有最高的线程优先级,内部由多个循环组成:
    主循环(loop)分为两类,每秒和每十秒的

    1. 每秒一次的操作:

      • 重做日志(redo log)缓冲刷新到磁盘,即使这个事物还没提交,这也是为什么大事物提交也很快
      • 合并插入缓冲(可能),并不是每秒都发生,引擎会判断前一秒io次数是否小于5,小于5表示压力小才会发送
      • 至多刷新100个缓冲池中的脏页到磁盘(可能) ,要判断脏页比例是否超过阈值,也就是上面提到过的 Dirty Page too much Checkpoint
      • 如果无用户活动,切换到后台循环(可能)
    2. 每十秒一次的操作:

      • 刷新100个脏页到磁盘(可能)
      • 合并至多5个插入缓冲
      • 将日志缓冲刷新到磁盘
      • 删除无用的undo页,会进行full purge操作,判断当前事物系统已经被删除的行是否可以删除。(是否还有一致性非锁定读)
      • 刷新100个或者10个脏页到磁盘 ,如果缓冲池中脏页比例大于70% 刷新100个,小于就刷新10%的脏页到磁盘
    3. 后台循环(backgroup loop)

    • 如果没有用户活动或者数据库关闭的情况,就会切换到这个线程,它的操作:
    • 删除无用的Undo页
    • 合并20个插入缓冲
    • 跳回到主循环
    1. 刷新循环(flush loop)
    2. 暂停循环(suspend loop)
    3. Page Thread 在新的版本(InnoDB 1.2.x)用来刷新脏页

三、特性

  1. 插入缓冲 (Insert Buffer)
    Insert Buffer

    • 和数据页一样也是物理页的一个组成部分,对于非聚集索引的插入和更新操作,不是每一次都直接插入到索引页,而是先判断其索引页是否在缓冲池中,如果在直接插入,如果不在就先放到一个Insert Buffer中。然后再以一定频率进行Insert Buffer和辅助索引叶子结点的合并操作,这时候能把多个插入操作一波处理。

    • 其实数据结构是一棵B+树,且全局只有一棵Insert Buffer B+树,负责对所有表的辅助索引进行Insert Buffer。这棵树放在共享表中心中,也就是ibdata1。所以在数据恢复时,试图通过独立表空间ibd文件恢复表中数据时,会导致check table 失败,因为表的辅助索引中的数据可能还在insert buffer中。所以通过ibd 恢复后,还需要repair table来重建表上的辅助索引。
      Insert Buffer需要满足两个条件:

      • 索引是辅助索引
      • 索引不唯一

    如果在进行大量非聚集索引数据插入时,数据库宕机了,恢复可能需要很长时间。

    索引不唯一是因为在插入buffer时候,数据库不会去查询记录的唯一性,否则又会变为离散插入

    Change Buffer
    InnoDB 1.0.x后支持 DML 操作的缓冲,也就是Insert Buffer、 Delete Buffer 、Purge Buffer(也是必须是非唯一辅助索引)
    更新一条数据分为两个过程,将记录标记删除(Delete Buffer)和真正删除(Purge Buffer)
    Insert Buffer Merge合并时机

    • 辅助索引页被读到缓冲池时 (就是在select 时先看下 buffer中是否有插入数据,有就合并进来)
    • Insert Buffer Bitmap(用来标记辅助索引页的可用空间)页追踪到该辅助索引页已无可用空间时 (也就是空间小于1/32 就强制读取这个页到缓冲池进行meege合并)
    • Master Thread (前面已经记录过这个插入缓冲)
  2. 两次写 (Double Write)
    用来保障数据页的可靠性的,在应用重做日志前,搞一个页的副本,当写入失效(就是写半截宕机了)发生时,先通过该副本进行恢复页,在进行重做,这就是double write.
    看下架构图
    MySQL 读书笔记 (二) InnoDB初探_第3张图片
    Double Write由两部分组成:

    • 内存中的doublewrite buffer ,大小为2M
    • 物理磁盘上的共享表空间中连续的128个页,即2个区(任何情况下每个区都是1M,一个区有64个连续页,每个页默认16k),大小为2M。

    过程:先将脏页copy到Doublewrite Buffer中,再通过buffer分为两次每次1M顺序写入共享表空间的物理磁盘上,然后马上调用fsync进行磁盘同步,避免缓冲写带来的问题。在写入完成后,再将doublewrite buffer中的页写入各个表空间文件中(离散写入)。

    数据恢复过程:崩溃后,引擎可以从共享表空间doublewrite找到该页副本,将其复制到表空间文件中,在应用重做日志。

  3. 自适应哈希索引 (Adaptive Hash Index)
    InnoDB存储引擎会监控对表上个索引页的查询,如果观察到建立哈希索引能带来查询速度提升,则建立哈希索引,称为自适应哈希(AHI)。

    AHI 是通过缓冲池B+树页构造而来,建立速度非常快,不需要为整张表建立哈希索引,只为热点数据建立。

局限性:只能搜索等值查询 如: where a=1,范围查询不会建立AHI

  1. 刷新邻接页 (Flush Neighbor Page)
    就是在刷新一个脏页的时候,会顺便检测下当前页所在的区是否有其他脏页存在,一起进行刷新。就可以通过AIO 将多个IO 合并成一个了。

  2. 异步IO (Async IO)
    MySQL 读书笔记 (二) InnoDB初探_第4张图片

你可能感兴趣的:(MySQL,Mysql基础)