MySQL之InnoDB存储引擎深入理解

参考自《MySQL技术内幕InnoDB存储引擎》
继前文对MySQL的存储引擎做一个全面的介绍之后,现在我们针对主流的InnoDB存储引擎深入理解。


一、InnoDB体系架构

InnoDB是事务安全的 MySQL存储引擎。支持ACID事务的储存引擎,特点是行锁设计、支持MVCC、支持外键、提供一致性非锁定读,同时被设计用来最有效地利用以及使用内存和CPU。
首先,在深入介绍InnoDB存储引擎之前,我们先来了解下InnoDB的体系架构:
在这里插入图片描述
后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB能恢复到正常运行状态。

1.1 后台线程

InnoDB存储引擎是多线程模型,因此其后台有多个不同的后台线程,负责处理不同的任务。

1.1.1 Master Thread

MasterThread是一一个非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插人缓冲(INSERT BUFFER)、UNDO页的回收等。

1.1.2. I0 Thread

在InnoDB存储引擎中大量使用了AIO (Async IO)来处理写IO请求,这样可以极大提高数据库的性能。而IOThread的工作主要是负责这些IO请求的回调处理。

1.1.3 Purge Thread

事务被提交后,其所使用的undolog可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。

1.1.4 Page Cleaner Thread

Page Cleaner Thread的作用是将之前版本中脏页的刷新操作都放人到单独的线程中来完成。而其目的是为了减轻原Master Thread的工作及对于用户查询线程的阻塞,进一步提高InnoDB存储引擎的性能。

1.2 内存

1.2.1 缓冲池

InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。我们都知道对磁盘的读取速度相较于内存是非常慢的,因此在内存与磁盘之间增加了一层缓冲池来提高数据库的整体性能。
缓冲池简单来说就是一块内存区域。在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程称为将页“FIX"(固定)在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。
注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为Checkpoint的机制刷新回磁盘。
具体来看,缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插人缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB 存储的锁信息( lockinfo)、数据字典信息(data dictionary) 等。不能简单地认为,缓冲池只是缓存索引页和数据页,它们只是占缓冲池很大的一部分而已。如下图很好地显示了InnoDB存储引擎中内存的结构情况。
在这里插入图片描述

1.2.2 LRU List、Free List和Flush List

我们知道缓冲池是一个很大的内存区域,存放各种类型的页。那么InnoDB是如何对这些内存进行管理的呢?
LRU算法(Latest Recent Used)介绍:即最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。
InnoDB在LRU算法的基础上做出一些优化,它在LRU列表中加入了midpoint位置。新读取到的页,虽然是最新访问的页,但并不是直接放人到LRU列表的首部,而是放入到LRU列表的midpoint位置。这个算法在InnoDB存储引擎下称为midpoint insertion strategy。
我们可以通过innodb_old_blocks_pct变量来设置该大小,如:
在这里插入图片描述
从上面的例子可以看到,参数innodb_old_blocks_pct 默认值为37,表示新读取的页插人到LRU列表尾端的37%的位置。在InnoDB存储引擎中,把midpoint之后的列表称为old列表,之前的列表称为new列表。可以简单地理解为new列表中的页都是最为活跃的热点数据
为什么不采用朴素的LRU算法,直接将读取的页放人到LRU列表的首部呢?
因为若直接将读取到的页放人到LRU的首部,那么某些SQL操作(索引或者数据扫描)可能会使缓冲池中的页被刷新出,从而影响缓冲池的效率。常见的这类操作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页通常来说又仅在这次查询操作中需要,并不是活跃的热点数据。如果页被放人LRU列表的首部,那么非常可能将所需要的热点数据页从LRU列表中移除,而在下一次需要读取该页时,InnoDB 存储引擎需要再次访问磁盘。
为了解决这个问题,InnoDB 存储引擎引人了另一个参数来进一步管理LRU列表,这个参数是innodb_ old_blocks_time, 表示页读取到mid位置后需要等待多久才会被加入到LRU列表的热端
注意:LRU列表用来管理已经读取的页,但当数据库刚启动时,LRU列表是空的,即没有任何的页。这时页都存放在Free列表(管理空闲页面的列表)中。当需要从缓冲池中分页时,首先从Free列表中查找是否有可用的空闲页,若有则将该页从Free列表中删除,放入到LRU列表中。否则,根据LRU算法,淘汰LRU列表末尾的页,将该内存空间分配给新的页。当页从LRU列表的old部分加入到new部分时,称此时发生的操作为page made young,而因为innodb_old_blocks_time的设置而导致页没有从old部分移动到new部分的操作称为page not made young.可以通过命令SHOW ENGINE INNODB STATUS来观察LRU列表及Free列表的使用情况和运行状态。
另外,当LRU列表中的页被修改后,称该页为脏页(dirty page),即缓冲池中的页和磁盘.上的页的数据产生了不-致。这时数据库会通过checkpoint机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。需要注意的是,脏页既存在于LRU列表中,也存在于Flush列表中。LRU列表用来管理缓冲池中页的可用性,Flush 列表用来管理将页刷新回磁盘,二者互不影响。

1.3 checkpoint(检查点)技术

在介绍checkpoint技术之前,先介绍下重做日志。
如果在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么数据就不能恢复了。为了避免发生数据丢失的问题,当前事务数据库系统普遍都采用了Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复。这也是事务ACID中D (Durability 持久性)的要求。
checkpoint技术主要解决以下几个问题:

  1. 缩短数据库恢复的时间;
  2. 缓冲池不够用时,将脏页刷新到磁盘;
  3. 重做日志不可用时,刷新脏页。

当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。故数据库只需对Checkpoint后的重做日志进行恢复。这样就大大缩短了恢复的时间。
当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。
重做日志出现不可用的情况是因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让其无限增大的。重做日志可以被重用的部分是指这些重做日志已经不再需要,即当数据库发生宕机时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。若此时重做日志还需要使用,那么必须强制产生Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置(强制刷新后,该部分重做日志便不需要了,然后就可以覆盖写入新的重做日志了)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值