Buffer Pool

Buffer Pool

如何调节磁盘与CPU的矛盾? 数据存放在表空间的页中,是存储在磁盘上,但是磁盘的速度很慢,所以数据库在处理数据时会把数据加载到内存中,当需要访问某个页的数据时,就会把完整的页全部加载到内存中,也就是说即使我们只需要访问一个页的一条记录,那也需要先把完整的页数据加载到内存中. 在进行完读写访问之后并不着急把该页对应的内存空间释放掉,而是将其缓存起来,这样将来再有请求访问该页面时,就可以省去IO开销

为了管理这些页,mysql为他们建立了控制信息块,每个缓存页对应的控制信息占用的内存大小是相同的,把控制信息占用的内存称为控制块,控制块和缓存页是一一对应的,他们都被放到Buffer pool中
Snipaste_20210522_091947.png

启动mysql的时候,会对buffer pool启动初始化操作,随着程序运行,会有数据页缓存到buffer pool上,
为了记录buffer Pool中哪些页是可用的,把所有空闲的缓存页对应的控制块作为一个节点放到一个链表中,
这个链表称为free链表
Snipaste_20210522_180649.png

有了这个free链表之后就好办事了,每当需要从磁盘加载一个页到Buffer Pool中时,就从free链表中取一个空闲的缓存页,并且把该缓存页对应的控制块信息填上,然后把该缓存页对应的free链表节点从链表中移除,表示该缓存页已经被使用了.

flush链表管理

如果我们修改了Buffer Pool中某个缓存页的数据,那么就和磁盘页不一致了,但是并不会马上刷新到硬盘上,那么如何管理这些刷新的脏页,mysql做出如下措施:凡是修改过的缓存页的控制块都加入到一个叫flush链表的结构中,假设某个时间点Buffer Pool中脏页的数量为n,那么对应的flush链表长这样:

Snipaste_20210522_222723.png

LRU链表

当Buffer Pool中不再有空闲的缓存页,需要淘汰最近很少使用的缓存页,为了按照最近最少使用的原则区淘汰缓存页的,所以这个链表可以被称为LRU链表,当我们需要访问某个页时:

  • 如果该页不在Buffer Pool中,在把该页从磁盘加载到Buffer Pool中的缓存页时,就把该缓存页对应的控制块作为节点塞到链表头部
  • 如果该页已经缓存在Buffer Pool中,则直接把该页对应的控制块移动到LRU链表头部

也就是说:只要我们使用到某个缓存页,就把该缓存页调整到LRU链表的头部,这样LRU链表尾部就是最近最少使用的缓存页

划分区域的预读

由于mysql存在预读机制:

  • 线性预读: 异步读取下一个区的页到Buffer pool
  • 随机预读: 如果Buffer Pool中已经缓存了某个区的13个连续页面,就会触发异步读取本区中所有的页面到Buffer Pool的请求

为了防止使用频率偏低的页面缓存到Buffer Pool中把使用频率非常高的页从Buffer Pool中淘汰掉

因为这种情况的存在,所以LRU链表按照一定比例分成两截:

  • 热数据区,或称为young区域
  • 冷数据区,称为old区域

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!