跳至主要內容

InnoDB 存储引擎

blacklad大约 5 分钟MysqlMysqlMysql 技术内幕

InnoDB 存储引擎

完整支持 ACID 事务的 Mysql 存储引擎 。

1 体系架构

1.1 内存池

InnoDB 存储引擎有多个内存块,组成了一个内存池。

  1. 维护线程需要访问的多个内部数据结构。
  2. 缓存磁盘上的数据,方便快速读取,修改之前也在这里缓存。
  3. 重做日志 redo log 缓存。

1.1.1 缓冲池

InnoDB 存储引擎是基于磁盘存储的,并将记录按页的方式管理,由于磁盘与 cpu 的数据相差过大,通过使用缓冲区(内存)提高整体性能。

读取页的操作时,首先从磁盘读到页放入缓冲池中,下次读取直接从缓冲池中读取。

修改数据库中的页操作时,先修改缓冲池中的页,然后以一定频率将已修改的数据文件刷新到磁盘上,不是每次操作都会刷新。

缓冲池中包括 索引页、数据页、undo 页、插入缓冲、自适应哈希所有、锁信息、数据字典信息等。InnoDB 允许有多个缓冲池实例,每个页通过哈希分配到不同的缓冲池。

1.1.2 LRU

缓冲池通过 LRU 算法进行管理, 即最频繁使用的页放在最前端,最少使用的放在尾端,当缓冲池满后,首先释放尾端的页。

为了防止将热点数据从 LRU 中移除,InnoDB 在列表中加入midpoint位置,新读取到的页首先放在 LRU 列表的 midpoint 位置。midpoint 之前的为new列表,之后的为 old 列表。old 列表中的数据只有读取达到一定次数才会移动到 LRU 列表的热端。

脏页

在 LRU 列表中的页被修改后,该页变为脏页,即缓冲池中的页和磁盘上的页的数据发生了不一致。同时定义了 Flush 列表管理脏页信息。

1.1.3 重做日志缓冲

Redo log buffer, 首先将重做日志信息放入缓冲区中,然后按一定频率将其刷新到重做日志中。

刷新策略

  1. Master Thead 每秒刷新到重做文件中。
  2. 每个事务提交时。
  3. 当重做日志小于1/2时。

1.1.4 额外的内存池

记录了一些 LRU、锁等信息。

1.2 CheckPoint

Write Ahead Log 策略,即当事务提交时,先写重做日志,再修改页。服务宕机时,可以通过重做日志完成数据的恢复,完成了事务的D(持久性)的要求。

由于重做日志不可能无限大,InnoDB 定义了 CheckPoint 检查点,CheckPoint 之前的页都刷新回磁盘。在需要恢复的时候只需对 CheckPoint 之后的重做日志进行恢复。

1.2.1 CheckPoint类型

  1. Sharp CheckPoint 在发生数据库关闭的时候将所有的脏页刷新会磁盘。
  2. Fuzzy CheckPoint
    1. 定时异步刷新。
    2. Page Cleaner线程检测LRU列表中是否有指定多的空闲页可用。
    3. 重做日志文件不可用,需要强制将一些页刷新回磁盘。
    4. 脏页数量太多。

1.3 后台线程

负责刷新内存池中的数据,保证缓冲池中的内存是最近的数据, 以及数据被刷新到磁盘中。保证在数据库发生异常的情况下能恢复到正常运行的状态。

后台有多个线程负责不同的任务。

1.3.1 Master Thread

将缓冲池中的数据异步刷新到磁盘,保证数据的一致性

  1. 日志缓冲刷新到磁盘
  2. 合并插入缓冲
  3. 刷新脏页到磁盘
  4. 删除无用的undo页

1.3.2 IO Thread

主要负责IO请求的回调处理,主要是 read、write、insert buffer、log 四个IO Thread。

1.3.3 Purge Thead

回收已经使用并分配的undo页

1.3.4 Page Cleaner Thread

将之前版本的脏页的刷新操作都放入单独的线程中执行

2 特性

2.1 插入缓冲

在 InnoDB 中,主键是唯一标识符,通常插入顺序是按照主键地都给的顺序插入的,所以插入聚集索引一般是顺序的,不需要磁盘的随机读取。而对于非聚集索引可能就不是按照顺序的了,插入数据时就需要离散地访问非聚集索引页,随机读取会影响插入的性能。

InnoDB 使用 Insert Buffer,对于非聚集索引的插入或者更新,不是直接插入索引页中,先判断索引页是否在缓冲中,如果在直接更新,不在则放在Insert Buffer中。然后再以一定的频率进行 InsertBuffer和辅助索引叶子节点的 merge 操作。

2.1.1 条件

  1. 索引是辅助索引。
  2. 索引不是唯一的(插入的时候不需要判断唯一性)。

2.2 两次写

保证数据页的可靠性。

2.2.1 问题

当数据库宕机时,如果 InnoDB 正在拍写入某个页到列表中,但是只写了一部分,就会发生部分页失效(也就是这个页已经损坏,不能通过重做日志恢复)。

2.2.2 Double write

在应用重做日志前,用户需要一个页的副本,当写入发生失效时,先通过页的副本来还原该页,再进行重做。

  1. 对缓冲池中的脏页刷新时,首先将脏页复制到内存中的 double write buffer,然后通过 double buffer 写入共享表空间的物理磁盘上,然后才进行同步磁盘。
  2. 如果写入磁盘过程中发生了崩溃,从共享表空间中的 double write 中找到该页的一个副本, 将其复制到表空间文件,再应用重做日志。

2.3 自适应哈希索引

InnoDB 会监控对标上个索引页的查询,如果判断建立哈希索引会提高速度,则建立哈希索引(自适应哈希索引)

数据库自优化的操作。

2.4 异步IO

数据库系统一般采用异步IO的方式处理磁盘操作。

  1. 异步io不需要阻塞等待查询结果。
  2. 可以进行IO merge 操作,若发现读的是同一个页,可能进行合并一次读取。

2.5 刷新邻接页

在刷新脏页的时候,如果发现该页所在区的其他页是脏页,那么一起被刷新。

上次编辑于:
贡献者: blacklad