7.BufferPool之缓存页

52 阅读6分钟

数据页:MySQL中抽象出来的数据单位

假设现在我们的数据库中一定有一片内存区域是Buffer Pool了,那么我们的数据是如何放在Buffer Pool中的?

我们都知道数据库的核心数据模型就是表+字段+行的概念,也就是说我们都知道数据库里有一个一个的表,一个表有很多字段,然后一个表里有很多行数据,每行数据都有自己的字段值。所以大家觉得我们的数据是一行一行的放在Buffer Pool里面的吗?

这就明显不是了,实际上MySQL对数据抽象出来了一个数据页的概念,他是把很多行数据放在了一个数据页里,也就是说我们的磁盘文件中就是会有很多的数据页,每一页数据里放了很多行数据,如下图所示。

image.png

所以实际上假设我们要更新一行数据,此时数据库会找到这行数据所在的数据页,然后从磁盘文件里把这行数据所在的数据页直接给加载到Buffer Pool里去。也就是说,Buffer Pool中存放的是一个一个的数据页,如下图。

image.png

磁盘数据页和BufferPool缓存页如何对应?

默认情况下,磁盘中存放的数据页的大小是16KB,也就是说,一页数据包含了16KB的内容。

而Buffer Pool中存放的一个一个的数据页,我们通常叫做缓存页,因为毕竟Buffer Pool是一个缓冲池,里面的数据都是从磁盘缓存到内存去的。

而Buffer Pool中默认情况下,一个缓存页的大小和磁盘上的一个数据页的大小是一一对应起来的,都是16KB。

磁盘按页读取和InnoDB的缓冲池设计关系?

(1)磁盘访问按页读取能够提高性能,所以缓冲池一般也是按页缓存数据;

(2)预读机制启示了我们,把一些“可能要访问”的页提前加入缓冲池,避免未来的磁盘IO操作;

所以我们看下图,我给图中的Buffer Pool标注出来了他的内存大小,假设他是128MB吧,然后数据页的大小是16KB。

image.png

缓存页对应的描述信息是什么?

接着我们要了解下一个概念,对于每个缓存页都会有一个描述信息,这个描述信息大体可以认为是用来描述这个缓存页的。

比如包含如下的一些东西:这个数据页所属的表空间、数据页的编号、这个缓存页在Buffer Pool中的地址以及别的一些杂七杂八的东西。

每个缓存页都会对应一个描述信息,这个描述信息本身也是一块数据,在Buffer Pool中,每个缓存页的描述数据放在最前面,然后各个缓存页放在后面。

所以此时我们看下面的图,Buffer Pool实际看起来大概长这个样子。

image.png

而且这里我们要注意一点,Buffer Pool中的描述数据大概相当于缓存页大小的5%左右,也就是每个描述数据大概是800个字节左右的大小,然后假设你设置的buffer pool大小是128MB,实际上Buffer Pool真正的最终大小会超出一些,可能有个130多MB的样子,因为他里面还要存放每个缓存页的描述数据。

大家可以想象一下,对于Buffer Pool而言,他里面会存放很多的缓存页以及对应的描述数据,那么假设Buffer Pool里的内存都用尽了,已经没有足够的剩余内存来存放缓存页和描述数据了,此时Buffer Pool里就一点内存都没有了吗?还是说Buffer Pool里会残留一些内存碎片呢?

如果你觉得Buffer Pool里会有内存碎片的话,那么你觉得应该怎么做才能尽可能减少Buffer Pool里的内存碎片呢?

答案是:当然有

因为Buffer Pool大小是你自己定的,很可能Buffer Pool划分完全部的缓存页和描述数据块之后,还剩一点点的内存,这一点点的内存放不下任何一个缓存页了,所以这点内存就只能放着不能用,这就是内存碎片。

那怎么减少内存碎片呢?

其实也很简单,数据库在Buffer Pool中划分缓存页的时候,会让所有的缓存页和描述数据块都紧密的挨在一起,这样尽可能减少内存浪费,就可以尽可能的减少内存碎片的产生了。

如果你的Buffer Pool里的缓存页是东一块西一块,那么必然导致缓存页的内存之间有很多内存空隙,这就会有大量的内存碎片了。

数据库启动如何初始化Buffer Pool?

数据库的Buffer Pool里面包含很多个缓存页以及缓存页的元数据。

同时每个缓存页还有一个描述数据或者叫缓存页的元数据。

那么在数据库启动的时候,他是如何初始化Buffer Pool的呢?

数据库只要一启动,就会按照你设置的Buffer Pool大小,稍微再加大一点,去找操作系统申请一块内存区域,作为Buffer Pool的内存区域。

然后当内存区域申请完毕之后,数据库就会按照默认的缓存页的16KB的大小以及对应的800个字节左右的描述数据的大小,在Buffer Pool中划分出来一个一个的缓存页和一个一个的他们对应的描述数据。

只不过这个时候,Buffer Pool中的一个一个的缓存页都是空闲的,里面什么都没有,要等数据库运行起来之后,当我们要对数据执行增删改查的操作的时候,才会把数据对应的页从磁盘文件里读取出来,放入Buffer Pool中的缓存页中。

Buffer Pool的预热机制

预热机制实际上是想让重启后的MySQL快速适应大规模的流量请求。

InnoDB 在服务器关闭时为每个缓冲池保存一部分最近高频使用的页面,并在服务器启动时恢复这些页面。

保存多大比例的缓存页由参数innodb_buffer_pool_dump_pct控制。

在启动时还原缓冲池,实际上会缩短预热的时间。

你可以通过下面的方式配置该参数

# 通过命令

SET GLOBAL innodb_buffer_pool_dump_pct=40;

# 通过文件

[mysqld]=40

参数innodb_buffer_pool_dump_at_shutdown控制 MySQL关闭时保存缓冲池的状态,默认为on的状态。

启动参数--innodb-buffer-pool-load-at-startup 表示启动MySQL的时候恢复缓冲池中的状态,默认也是开启的