1、innoDB存储引擎体系架构
如上图所示,innoDB存储是基于磁盘存储的,并且其中的记录以页的方式进行管理,但为什么要引入一个内存池呢?
其目的就是为了协调CUP速度与磁盘速度的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能(简单来说就是通过内存的速度来弥补磁盘速度较慢对数据库性能的影响)
2、内存池的管理
既然内存池能提高数据库的整体性能,那么innoDB是怎么对这块内存区域进行管理的呢?这里就要介绍一种算法和一种机制
2.1、LUR列表
上图就是一个LUR列表,上图的LUR链表氛围new(热点)区和old(淘汰)区,new和old之间的位置称为midpoint,其余的还有free(空闲)列表等
先来说查询情况,在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,下一次在读相同页的时候,首先判断该页是否在缓冲池,若在缓冲池中,则直接读取该页,否则读取磁盘上的页
对于数据库中页的修改操作,首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上,页不是在每次发生更新时触发的,而是根据一种checkpoint的机制刷新会磁盘
2.2、LUR(最近最少使用)算法
2.2.1、LUR列表是通过什么方式管理数据的?
LUR(最近最少使用)算法,当新查询进来时,innoDB会从free列表中拿出可用的页,放到LUR列表中,然后从free列表删除该页,如果LRU列表溢出,那么就会淘汰掉LRU列表(old区)末尾的页,同时把新的页放到old区列首
2.2.2、old区的数据什么时候能加入到new区?
在old列表存留了innodb_old_blocks_time所配置的时间之后下一次查询还能在old区中命中缓存,则加入到new区,如果new区溢出,则溢出的页则放到old区
2.3、Checkpoint机制
Checkpoint机制指得就是将缓冲池的脏页数据刷新到磁盘
如果在缓冲池将页的数据刷新到磁盘时发生了宕机,那么数据就无法恢复了,所以事务数据库系统都会采用一种Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页,因为宕机而导致数据丢失时,可以通过重做日志完成数据的恢复
2.3.1、Checkpoint机制触发点
(1)Sharp Checkpoint
在数据库关闭时,将所有的脏页都刷新到磁盘,如果在数据库运行时使用Sharp Checkpoint,那么数据库的可用性就会收到很大的影响
(2)Fuzzy Checkpoint
每次刷新一部分脏页,因此InnoDB存储引擎内部使用Fuzzy Checkpoint进行页的刷新
2.3.2 Fuzzy Checkpoint
Fuzzy Checkpoint 有一下4种方式
(1)Master Thread Checkpoint
在Master Thread中发生的Checkpoint,以每秒或每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘,过程是异步的,所以InnoDB存储引擎可以机芯其他操作,用户查询线程不会阻塞
(2)FLUSH_LRU_LIST Checkpoint
InnoDB存储引擎需要保证LRU列表中需要有100个空闲页可以使用(为了保证有足够的可用空间给用户查询线程中,不会阻塞线程的查询操作)
如果没有100个空闲页,LRU算法会清除掉LRU列表(old区)尾端的页,此时如果有脏页,则需要进行CheckPoint
(3)Async/Sync Flush Checkpoint
指重做日志不可用时(这部分日志已经不再需要了,可以进行清除),刷新脏页到磁盘(如果这时的重做日志还有脏页,则必须要刷新到磁盘)
(4)Dirty Page too much Checkpoint
脏页数据太多,导致InnoDB存储引擎强制进行Checkpoint,目的总的来说还是为了保证缓冲池有足够可用的页
2.3.2、Checkpoint机制解决的问题
(1)缩短数据库的恢复时间
当数据库发生宕机时,数据库不需要重做所有的日志,因为checkpoint之前的页都已经刷新回磁盘了,所以只需要对checkPoint后的重做日志进行恢复(增量恢复)
(2)缓冲池不够用时,将脏页刷新到磁盘
因为LRU算法会清楚掉最近最少使用的页,如果清除的包含脏页,那么需要强制执行checkPoint,将脏页刷新到磁盘
(3)重做日志不可用时,刷新脏页
重做日志不可用指得是:这部分日志已经不再需要了,可以进行清除(节省空间,新的重做日志可以复用这部分的空间),但是如果这部分的日志还有脏页数据(需要使用),那么必须强制产生Checkpoint,将缓冲池中的页至少刷新到磁盘到当前重做日志的位置
参考资料:
MySQL技术内幕InnoDB存储引擎第二版
https://blog.51cto.com/14227759/2384690?source=dra
https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html