InnoDB存储引擎之缓冲池原理
对于InnoDB存储引擎体系架构不清楚的朋友可以看看这篇博客:
MySQL—InnoDB存储引擎体系架构——详解
1.缓冲池概述
- InnoDB存储引擎是基于磁盘存储的,将其中的记录按照页的方式进行管理,因此可以将其看做基于磁盘的数据库系统。但是在数据库系统中,由于CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高整体性能(因为与CPU IO和与磁盘 IO的速度差距非常大)
- 缓冲池简单来说就是一块内存,通过访问缓冲池来进一步访问磁盘,弥补磁盘速度较慢的影响。
- 在数据库读取页的操作时,首先判断该页在不在缓冲池中,如果不在那就首先将该页从磁盘读取到缓冲池中,然后在缓冲池中进行查询等。下次读相同页的时候,就只需要在缓冲池中读取即可(前提是该页还在缓冲池内,也有可能被移除了)。
- 对于数据库页的修改操作,则首先修改在缓冲池中的页,修改页但是此时还没有刷新回磁盘,称为脏页。InnoDB并不是修改之后立即刷新回磁盘,而是以一定的频率和机制刷新回磁盘,这种触发机制成为CheckPoint(后面会更新CheckPoint的文章)
2.缓冲池组成
- 缓冲池共有六部分组成:
1)数据页
2)索引页
3)插入缓冲
4)锁信息
5)自适应哈希索引
6)数据字典信息 - 在缓冲池中,数据页和索引页占了很大一部分
- 从InnoDB 1.0.x版本开始,允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。这样做的好处就是减少数据库内部的资源竞争,增加数据库并发处理的能力。
- 对于插入缓冲,是InnoDB关键特性之一,可以单独看这篇文章:
InnoDB存储引擎关键特性之插入缓冲——详解
3.缓冲池的内存管理机制
- 我们现在知道了缓冲池是一块很大的内存区域,其中存放各种类型的页。那么InnoDB对这块内存是如何进行管理的呢?
3.1 LRU List
- 通常来说,数据库中的缓冲池是通过LRU(Latest Recent Used, 最近最少使用)算法来进行管理的。
- 即最频繁使用的页放在LRU列表的前端,最少使用的页放在LRU列表的尾端,当缓冲池中不能存放新读取的页时,就首先释放LRU列表中的尾端的页。
InnoDB中存储引擎中对LRU算法进行了一些优化:
- InnoDB在LRU列表中引入了midpoint参数。新读取的页并不会直接放在LRU列表的首部,而是放在LRU列表的midpoint位置。在默认配置下,这个位置在LRU列表的5/8处,我们将mid之前称为热端(热点数据),mid之后称为冷端
- InnoDB还引入了innodb_old_blocks_time参数,即当新页放在midpoint上之后,必须过了等待这么久的时间后如果还存活在LRU列表上,才可以被调到热端上。
优化的原因:
- 为什么引入midpoint参数呢?因为有可能这次读取的新页仅仅是在这次sql操作查询中需要用到,并且之后用到的概率非常小,如果把这样的页直接放在LRU列表的首部,那么就可能会将比其更加热点的页移到后面甚至是移除LRU列表
- 为什么引入innodb_old_blocks_time参数?针对于某些sql操作,这些操作可能会访问表中的许多页,甚至是全部的页。那么这些页也仅仅是在这次查询中要用到,并不是活跃的热点数据,所以设置一个等待时间,如果过了这个等待时间,这些页还存活在缓冲池中的话,才可以被移动到热端。
3.2 Free List
- LRU列表用来管理已经读取的页,但当数据库刚启动的时候,LRU列表是空的,即没有任何的页。这时页都存放在Free List中。
- 当需要从缓冲池分页时,首先从Free列表中查找是否有可用的空闲页,若有则将该页从Free列表中删除,放入LRU列表中。 否则根据LRU算法,淘汰LRU列表尾端的页,将内存空间分配给新的页
- 注意的就是:缓冲池中的页还可能被分配给自适应哈希索引,锁信息,插入缓冲页等,这部分的页不在LRU列表中,不需要LRU算法进行维护
3.3 Flush List
- 在LRU列表中被修改的页,称为脏页,即缓冲池中的页和磁盘上的页数据产生了不一致,这时候数据库会通过CheckPoint机制将脏页刷新回磁盘。
- Flush列表中的页即为脏页列表。需要注意的是,脏页即存在于LRU列表中,也存在与Flush列表中
3.4 LRU对压缩页的管理
- InnoDB存储引擎从1.0.x版本开始支持压缩页的功能,即将原本16KB的页压缩为1KB,2KB,4KB,8KB
- 由于页的大小变化,LRU列表也有了些许的改变。对于非16KB的页,是通过unzip_LRU列表进行管理的
unzip_LRU列表的内存管理: 通过 伙伴算法 实现不同压缩页大小的管理
-
例如需要从缓冲池中申请页为4KB大小,过程如下:
1)首先检查4KB的unzip_LRU列表是否有可用的空闲页
2)若有,则直接使用
3)若没有则检查8KB的unzip_LRU列表是否有可用的空闲页
4)如果有,则将一页分为两个4KB的页,然后存放到4KB的unzip_LRU列表中
5)如果没有,则从LRU列表中申请16KB的页,将其分为一个8KB,两个4KB的页去分配
4.总结
- 缓冲池的内存管理最关键的就是LRU列表的实现!以及其对LRU算法的优化设计,引入的两个参数