InnoDB的Buffer Pool详解 【Mysql Day 2】

132 阅读4分钟

缓存的重要性

我们知道内存的速度很快,但是磁盘的速度慢的一批,那么不可能让内存去等磁盘慢慢搬数据,那么就需要一个东西,让我们尽可能少去找磁盘要数据,能找个地提前存起来一片连续的数据,那么岂不是就减少了IO开销嘛,这就是缓存的作用

Buffer Pool是干啥滴?

简单来说就是为了缓存那些连续的数据页而向操作系统申请的以chunk为基本单位申请的一片连续内存,,给它起了个名叫buffer pool(缓冲池) 可以通过innodb_buffer_pool_size设置其大小,默认是128MB

Buffer Pool 内部组成

简单来说就是将申请来的内存划分成若干个页面,页面大小与表空间里的页大小一致,都是16KB。为了与磁盘空间的页分开,这里叫它缓冲页,其中通过许多对应的控制块和控制块管理的缓冲页构成了Buffer Pool。

多个Buffer Pool实例

我们都知道mysql能抗住高并发,那么只有一个Buffer Pool实例明显是扛不住的?那么它如何解决的呢?

  • 当一个Buffer Pool很大时,把它进行了拆分成小Buffer Pool,每一个都是一个Buffer Pool实例,他们都是独立的,互不影响
  • 通过innodb_buffer_pool_instances设置实例的个数

Buffer Pool的三个阶段

初始化

刚开始时,Buffer Pool里是空的,那么就需要从磁盘中读取数据到Buffer Pool的缓冲页中,那么哪些缓冲页是我能用的呢?那么就要引入一个 free链表

free链表

作用:记录Buffer Pool中哪些缓存页是可以用的,每个空闲的缓存页的控制块会来这个链表排队。

控制块中会包含free链表的前后指针

有修改操作

当我们修改了Buffer Pool中某个缓冲页的数据,它就与磁盘页的数据不一致了,这样的缓冲页就是脏页,那么我们需要将其写回磁盘,那么不可能来一个脏页我就立即往磁盘刷吧,磁盘速度又那么慢是吧,明显不合理,那么就要引入第二个链表了--flush链表

flush链表

作用:记录那些是脏页的缓冲页,将其控制块在这里排队

结构和free链表没啥差别

Buffer Pool满了

问题来了:移除哪些旧的缓冲页?用什么方式?

  • 在Innodb中采用了LRU链表来记录这些缓冲页
LRU链表
简单版
  • 经常使用的那种缓冲页放在LRU链表的前面,那种不经常使用的就放后面,空间不够了就把链表后面的那些缓冲页移除就行。
  • 预读问题:innodb为了减少io请求,在你读取某一页时,会把那一页的连续几个页都缓冲到Buffer Pool里,它觉得你可能会用到那一页后面的数据页就给你一股脑都塞进Buffer Pool里,那么岂不是Buffer Pool就很容易被一些用不到的缓冲页给填满了?
  • 全表扫描问题:把我经常使用的缓冲页给我挤到链表末尾去了,很容易就被移除了
划分区域的升级版
  • 使用频率非常高的缓冲页:热数据
  • 使用频率不高的缓冲页:冷数据
  • 比例:热数据区(young)占5/8 ,冷数据(old)区占 3/8
再优化版
  • 规定:某个页面第一次加载到Buffer Pool中的缓冲页中,该缓冲页的控制块会放到old区的头部
  • 规定:在对于处于old区的缓冲页进行第一次访问时,就在其控制块记录一下访问时间,如果后续的访问时间与第一次访问时间在某个时间间隔内,那么该页面就不会从old区移动到young区的头部,否则将它移动到young区的头部
  • innodb_old_blocks_time设置其间隔时间

4.再再优化版

  • 在这就不细说了,思路都是差不太多的