InnoDB 的缓冲页管理

InnoDB 的缓冲页管理

Nov 11, 2021
数据库, MySQL

Innodb 存储引擎将存储的数据都是以页的形式存放在表空间中,表空间是 InnoDB 对数据文件的抽象,说到底还是存储在磁盘上,我们都知道 CPU 的速度非常快,不会直接操作磁盘,于是 InnoDB 设计了一个缓存池(Buffer Pool)的机制,有数据库操作时,现将磁盘的文件导入内存进行操作,然后再通过一定机制回写到磁盘上。

缓存池是内存中的一段连续空间,其中一大部分被分为若干缓冲页,缓冲页与表空间的页一致,具体来看,缓冲池中缓存的数据类型还有:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lockinfo)、数据字典信息(data dictionary)等。不能简单地认为,缓冲池只是缓存索引页和数据页,它们只是占缓冲池很大的一部分而已。

那这些缓冲页是如何被管理的呢?

LRU List #

缓冲池是通过 LRU 算法进行管理的,即最频繁使用的页在 LRU 列表的最前端,最少使用的页在 LRU 列表的尾端。当缓冲池不能存放新读取的页时,会首先释放尾端的页。

在 InnoDB 的存储引擎中,LRU 列表中还加入了 midpoint 位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到 LRU 列表的首部,而是放入到 LRU 列表的 midpoint 位置,默认情况下是 5/8 处,这也就是常说的 LRU 列表热端(new)和冷端(old)的分界点了。参数innodb_old_blocks_time 表示页读取到 mid 位置后要等待多久才能被加入到 LRU 列表的热端。

如此操作,就可以保证 LRU 的热端不会被每一次读取而频繁变动,而是根据读取频率最高的放到热端。

Free List #

LRU 列表用来管理已经读取的页,但当数据库刚启动时,LRU 列表是空的,即没有任何的页。这时页都存放在Free 列表中。当需要从缓冲池中分页时,首先从 Free 列表中查找是否有可用的空闲页,若有则将该页从 Free 列表中删除,放入到 LRU 列表中。否则,根据 LRU 算法,淘汰 LRU 列表末尾的页,将该内存空间分配给新的页。

Flush List #

在 LRU 列表中的页被修改后,称该页为脏页(dirtypage),即缓冲池中的页和磁盘上的页的数据产生了不一致。这时数据库会通过 Checkpoint 机制将脏页刷新回磁盘,而 Flush 列表中的页即为脏页列表。脏页既存在于 LRU 列表,也存在于 Flush 列表。

Checkpoint 机制 #

checkpoint 意为检查点,在数据库多个场景有用到,主要在:

  • 当数据库宕机时,数据库只针对 Checkpoint 之后的重做日志进行恢复。
  • 缓冲池不够用时,将脏页刷新到磁盘

InnoDB 的 Checkpoint 分为两种:

  • Sharp Checkpoint 发生在数据库关闭时将所有的脏页都刷新回磁盘。
  • Fuzzy Checkpoint 在数据库运行时进行页的刷新,只刷新一部分脏页。

参考 #

MySQL技术内幕:InnoDB存储引擎(第2版)

本文共 1047 字,上次修改于 Jan 16, 2024,以 CC 署名-非商业性使用-禁止演绎 4.0 国际 协议进行许可。

相关文章

» MySQL 的日志种类

» 数据库的索引

» 数据库的事务

» 数据库的锁

» 数据库的 join 连接类型