Mysql InnoDB Buffer Pool

参考书籍《mysql是怎样运行的》系列文章目录和关于我
一丶为什么需要Buffer Pool对于InnoDB存储引擎的表来说,无论是用于存储用户数据的索引,还是各种系统数据,都是以页的形式存放再表空间中,归根结底还是存储再磁盘上 。因此InnoDB存储引擎处理客户端的请求是,如果需要访问某个页的数据,需要把完整的页数据加载到内存中,即便是只需要一条数据,也需要把整个页的数据加载到内存后进行读写访问 。如果没用缓存那么一条sql需要进行多次的磁盘IO操作,如果在读写页后将其缓存在内存中,便可以减少这种磁盘IO提高mysql性能 。
二丶InnoDB Buffer Pool及其内部组成InnoDB 会在mysql服务器起到是就向操作系统申请一块连续的内存,(innodb_buffer_pool_size可以控制大小,单位字节)用来对InnoDB的页做缓存操作 。
Buffer Pool对应一片连续的内存被划分为若干个页面,页面的大小和InnoDB页面大小一致(16kb)每一个buffer pool 页都对应一些控制信息(表空间编号,页号等)这些控制信息被抽象为控制块(后文我们把buffer pool的页称为缓冲页,和表空间中页做区分)

Mysql InnoDB Buffer Pool

文章插图
三丶空闲缓冲页管理——free 链表从磁盘上读取一个页到buffer pool中时,应该把这个页缓存到哪儿昵 。buffer pool的做法时将空闲的缓冲页对应的控制块作为一个节点放在链表中,这个链表称作free链表 。
Mysql InnoDB Buffer Pool

文章插图
其中有一个基节点负责记录链表的头和尾,每一个空闲的页都将在free 链表中串联起来 , 每当innodb需要缓存一个页的时候,就通过基节点获取一个空闲的buffer pool 缓冲页,然后在这个缓冲页中记录下表空间,页号之类的信息 。然后把缓冲页对应的free链表节点移除 。
在缓存一个页的时候,还需要判断当前页是否已经被缓存,innodb 对已经缓存的页,根据其表空间和页号两个值作为hash的key , 建立hash表,这样可以很快的进行判断 。
四丶缓冲页刷盘——flush链表当innodb修改一个磁盘上的页并缓存到buffer pool中 , 这时候内存中缓存的数据和磁盘就不一致这种页称为脏页 。如果每次执行完修改都立马将数据刷新到磁盘中的页会影响到程序的性能,所以innodb不会立马刷新到磁盘 , 而是使用flush链表将脏页对应的控制块串联起来
Mysql InnoDB Buffer Pool

文章插图
五丶缓冲空间不够怎么办——LRU链表管理1.简单的LRU链表buffer pool的大小毕竟是有限的 , 当free 链表中不存在更多空闲的缓冲页了,这时候就需要采取一些淘汰策略对一些无用的缓冲页进行淘汰 。
这里就是涉及到两个问题:什么样的缓冲页是无用的,如何维护这些缓冲页来实现此淘汰策略 。这时候自然是使用LRU算法(最近最少使用)淘汰最近最少使用到缓冲页 。LRU算法使用一个链表来实现,当innodb访问某个页的时候:
  • 如果该页不在buffer pool中 , 那么把该页从磁盘加载到buffer pool中的缓冲页是,就把该页的控制块放在LRU链表的头部
  • 如果该页已经在buffer pool中 , 那么移动节点到LRU链表头部
这样可以实现,被使用到缓冲页,会尽量靠近LRU链表的头部,自然而然尾部便是最近最少使用到的数据 。LRU算法基于——最近使用到的数据,后续也会到使用到的思想,使用LRU可以提高Buffer pool缓存的命中率 。
2.简单LRU链表无法解决的问题