ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一文详解InnoDB最核心组件Buffer Pool(二)

2021-09-30 17:34:00  阅读:184  来源: 互联网

标签:缓存 Buffer free 链表 InnoDB 数据 Pool


前文我们已经讲了Buffer Pool最基础的数据存储单元,缓存页。缓存页里存储的就是一行一行的数据,同时每个缓存页都对应了一个描述数据。

那MySQL启动的时候,是如何初始化Buffer Pool的?又是如何从磁盘加载数据文件到缓冲页的呢?

MySQL启动的时候,会按照配置在内存中给Buffer Pool分配一块内存,作为Buffer Pool的内存空间。然后会按照默认的16K缓存页大小,在Buffer Pool中划分出一个个的缓存页和与它们一一对应的描述数据块,这些描述数据块比较小。

此时这些缓冲页都还是空的, 然后Buffer Pool会搞出一个free链表,把这些描述数据块放到这个free链表中,这个free链表是公用的,如果有多个Buffer Pool,它们会公用这个free链表。

图片

如上图,这个free链表是个双向链表,它里面就是各个缓存页的描述数据块的指针,指向了各个Buffer Pool中的描述数据。

另外,这个free链表还有一个基础节点,它会引用双向链表的头节点尾节点,同时会记录free链表中有多少个节点,也就是多少个空闲的缓冲页。

现在有了free链表,我们从磁盘加载数据页到Buffer Pool缓存页的时候,就可以从free链表里获取一个描述数据块,然后就可以对应的获取到这个描述数据块对应的空闲缓存页。

图片

把磁盘上的数据页加载到Buffer Pool的缓存页后,同时会把相关的描述数据写入缓存页的描述数据块去,比如这个数据页所属的表空间,页号,最后从free移除这个节点。

可能有同学疑问,我怎么知道数据页有没有加载到Buffer Pool?

我们在操作数据的时候,肯定要先看下这条数据对应的数据页是否已经加载到缓存页,如果已经加载了,就直接使用了。如果没有加载,就从free链表中找到一个空闲的缓存页,写入描述数据,再从free链表中移除这个节点。

其判断依据,数据库的一个哈希表。

这个哈希表,用表空间号 + 数据页号作为key,缓冲页地址作为value。

当你要使用一个数据页时,先在这个哈希表里判断下这个页是否存在。如果存在,就直接根据value找到缓冲页了,如果不存在,就要去加载,然后把这个页的信息写入哈希表中。

图片

当我们把数据页加载到缓存页后,就可可以操作数据了,当你完成了对缓存页数据的更新,那么缓存页的数据就和磁盘上的数据页里的数据不一致了,怎么刷到磁盘上去呢?

不能每次修改一条数据,就把所有缓存页都刷到磁盘去吧?有的可能只是读取才加载到Buffer Pool,并没有修改,没必要刷盘啊。

其实InnoDB里还有个flush链表,这个flush链表跟free链表类似,其每个节点保存的也是描述数据块的指针,当某个缓存页修改了,就把它对应的描述数据块放到flush链表中。如下图所示:

图片

通过上面的分析,我们基本能知道,MySQL启动的时候,会分配一块Buffer Pool内存区,然后划分出一块一块的缓存页,这些页都是空的,都会加入到free链表中。当要访问数据的时候,先判断下缓存页是否在数据页缓存哈希表中,如果在就直接使用了,如果不在,就从磁盘文件中加载数据页,然后从free链表中删除这个节点。完成修改后,就把这个缓存页加入到flush链表,等待刷入磁盘。

接下来,我们需要思考一个问题,我们不停的把磁盘上的数据页加载到free链表中去,free链表就会不停的移除空闲缓存页,总会有free链表没有空闲缓存页的时候,这时候还要加载数据页到空闲缓存页怎么办?

Buffer Pool大小是固定的,free链表在初始的时候,也初始化了所有的空闲缓存页,数量也是固定的,当所有缓存页都被填满了后,就需要淘汰点一些缓存页。

淘汰哪些呢?

这就要引入缓存命中率了。

假设有两个缓存页,一个缓存页,1分钟之内访问了100次,另一个缓存页1分钟之内只有访问了10次,这时我们就可以说前者缓存命中率比后者高。

这时候必须要淘汰一个缓存页,肯定是淘汰掉缓存命中率低的那个了。

说到这里,很多同学肯定会想到它了,没错,就是LRU算法。

LRU,least recently used,最近最少使用的意思。

InnoDB通过引入LRU链表,就可以知道哪些缓存页最近最少被使用,当你要淘汰一些缓存页的时,就知道淘汰哪些缓存页了。

图片

LRU链表的特性就是,你只要访问了某个节点,它就会把这个节点移动到链表头部去,也就是说最近被访问的节点一定在LRU链表的头部,访问少的节点,自然到了链表的尾部。

这样的话,当缓存页长时间没有被访问,就处于LRU链表的尾部,当要淘汰缓存页的时候,这些访问频率低的节点就可以淘汰掉,重新把需要的磁盘文件数据页加载到空闲的缓存页里来。

总结:

本文引入了3个链表:

free链表,管理Buffer Pool中空闲的缓存页;

flush链表,管理修改过需要刷入磁盘文件的缓存页;

lru链表,用lru算法管理哪些缓存页访问频率高,哪些缓存页访问频率低,当没有空闲缓存页的时候,就可以把访问频率低的缓冲页过期掉,从新加载需要的缓存页了。

END

标签:缓存,Buffer,free,链表,InnoDB,数据,Pool
来源: https://blog.csdn.net/a1064447034/article/details/120570030

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有