缓存的重要性
我们知道内存的速度很快,但是磁盘的速度慢的一批,那么不可能让内存去等磁盘慢慢搬数据,那么就需要一个东西,让我们尽可能少去找磁盘要数据,能找个地提前存起来一片连续的数据,那么岂不是就减少了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.再再优化版
- 在这就不细说了,思路都是差不太多的