一.概述
在前面的讲述中,我们已经连接到innodb引擎中,会有缓冲池(buffer pool),undo log,redolog,binlog,并且在修改事务的时候,会把数据相应的写到对应的日志中,这篇文章,我们将继续深入理解buffer pool内部结构
二.Buffer pool 内部结构
2.1 buffer pool 大小
默认大小是128M,这个设置一般而言,对于线上部署的项目是有些偏小的,如果线上是16核32G,可以设置buffer pool的大小为2G,或者根据压测结果合理设置
2.2 buffer pool存储数据
我们知道数据库模型是 表+字段+行,一个表又会有很多行数据,每行数据又有多个字段,可能有人认为数据就是一行一行存放在bufferpool中,但是实际上又不是这种; 实际上mysql对数据又抽象了一层叫数据页的概念,就是会把很多数据存放在数据页中,在查询和更新数据的时候,是以数据页为单位进行操作的,如图所示:
实际上,当我们要更新一行数据的时候,会把包含这行数据所在的数据页,一起加载到buffer pool中,如下图:
一个数据页大小是16k,当数据页存入缓冲池中,叫做缓存页,并且每个缓存页都会有一个对应的描述信息,如下图:
每个缓存页对应的描述数据,大概占缓存页大小的5%左右,也就是800字节,如果使用默认的buffer pool是128M,实际上buffer pool大小会超过一些,大概有130多M,因为会存放一些描述信息.
2.3 buffer pool 哪些是空闲?
在mysql服务起来的时候,mysql会向操作系统申请128M的空间作为buffer pool,最开始的时候,里面都是空的,但是在运行很多sql后, 就会不停的把数据从磁盘读取到buffer pool中,同时IO线程也会定时的刷新bufferpool数据到磁盘中,必然会涉及一个问题,哪些缓存页是空闲的,因此数据库会设计一个free链表,他是一个双向链表接口,在这个free链表中,每个节点就是一个空闲的缓存页的描述信息的地址,也就是说,只要这个缓存页是空闲的,他的描述信息地址就会放在这个free连中
2.4 怎么知道数据页是否已经加载到缓存页中
我们在crud的时候,首先看数据页是否被缓存,如果没有缓存,就会从free中找一个空闲页,然后从磁盘读取数据,写入缓存页中,把这个缓存页从free链表中删除,如果已经被缓存过,就直接使用,那么是怎么知道是都被缓存的呢??
数据库还有一个hash结构,key = 表空间号+数据页号,value =缓存页的地址
当你要使用一个数据页时候,通过"表空间+数据页号"去hash中查一下,如果有就说明被缓存过了,如图所示
2.5 flush链表: 记录那些缓存页被修改
数据被加载到缓存页后,程序执行的时候,会先对内存中数据进行修改,然后在某个时间将数据刷新到磁盘中,这个时候,就需要有一个地方记录哪些缓存页被修改了,参考free链表,有一个flush链表,会记录哪些缓存页被修改,如下图所示:
三.淘汰策略
通过上面的讲解,我们知道在缓冲池中,会有free链表记录哪些是空闲的缓存页,fursh链表记录哪些是修改过数据的缓存页,会有这样一个问题:
在刚开始时候,所有的缓存页都在free链表中,随着数据不停的从磁盘加载到内存中,free链表的数量会越来越少,最后一刻,free链表为空了,这个时候说明已经没有可用的缓存页了,怎么办??
这个时候,就需要淘汰一些缓存数据,就是把缓存页中,修改过的数据给刷新到磁盘中,然后这个缓存页就能被再次使用了,问题又来了,要先清空哪些缓存页呢??
3.1 LRU判断缓存是否需要清空
作为开发人员