管理Buffer Pool的链表---Free、Flush、Lru链表

·  阅读 665
管理Buffer Pool的链表---Free、Flush、Lru链表

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

关于buffer pool的介绍我在上一篇里面就介绍了这里就不再介绍了,好了那么就直接进入主题。

LRU链表

Lru链表本质是个双向循环链表,结构如下:

image.png 根据空间局部性原理,磁盘或者数据库在读取数据的时候会预读该数据附近的数据,而且mysql中也存在着预读机制。那么如果按照简单的Lru链表,直接把最近最新访问的页面放入Lru链表中的话,读取一个数据页的时候,它会预读可能没必要的好多数据页,这些数据页可能到失效你都不会用到,但是却把之前一些最近最常访问的页面给淘汰掉了。这就违背了Lru链表的初衷。当然针对这个问题,mysql使用了Lru链表的变体

mysql中lru链表

Buffer Pool使用lru链表的变体作为进行管理,当需要空间将新页面添加到缓冲池时,最近最少使用的页面将被移除,并将新页面添加到列表的中间。这个中点插入策略将列表视为两个子列表:

  • 在头部保存最新最近访问的子列表。
  • 在尾部保存最近最少访问页面的子列表。

具体结构如下图:

image.png

其中new sublist中保存最近经常访问的页面,而old sublist中保存最近最少使用的页面,old sublist中的页面有可能被淘汰替换。

默认情况下new sublist占比5/8,old sublist占比3/8.

lru链表的页面读取机制

在mysql的lru链表中,当页面读入buffer pool时,首先将其插入中点(old sublist的头部)。页面被读取分为两种情况:

  • 用户进行数据库操作(sql查询访问页面)
  • 存储引擎自动执行预读操作

访问old sublist中的页面会使其移动到new sublist列表的头部。如果是预读操作读取该页面,则不会立即进行第一次访问,可能在该页面被淘汰之前都不会进行第一次访问,当然正常情况下读取old sublist的缓存页会使该缓存页上升到new sublist成为热数据。不过在读取大量数据的情况下,也就是有许多缓存页被预读到old sublist中的情况下,在不到x秒的情况下你又访问了它,那么在这段时间里面访问的缓存页也不会被提升到new sublist中。这个x秒由参数innodb_old_blocks_time控制。

数据库操作时,buffer pool中没有被访问的页面会向列表的尾部移动。old sublist和new sublist中的页面都会随其他页面的更新而老化。最终没有被用到的页面到达old sublist的尾部并被淘汰。

Free链表

Free list由基节点和子节点组成,基节点存储了free list有多少个描述信息块,也就是有多少个空闲缓存页。子节点有控制块,控制块是空闲页的一个对象,它用来定位空闲页。

Free List中保存的是空闲的页,当需要从缓存池中分页时,访问Free list查看是否有空闲的页,若有则取得该页并将该页分配给Lru list,然后在Free list中删除该页。没有的话则lru释放其尾部的缓存页,将该内存分配给新页。

image.png

Flush链表

Flush List 是一个双向链表,用于保存被修改过的缓存页的描述信息块,具体作用是帮助我们找到需要刷盘的缓存页,也就是脏页。(脏页是指数据和磁盘上的数据不一致的缓存页,脏页中的数据是需要刷盘到磁盘中的)Flush list也有一个基节点,用于存储描述信息块的数量。

mysql中有一个线程,专门用于定时去flush list中查找脏页,然后把flush list中的缓存页刷入磁盘中,然后缓存页从flush list中删除,并添加到free list中。具体流程可以参考下图:

image.png

结语:至此mysql中管理buffer pool的lru、free、flush链表的介绍到此结束。

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改