InnoDB存储引擎是一个完整支持ACID事务的MySQL存储引擎, 其特点是 行锁设计, 支持MVCC, 支持外键, 提供一致性非锁定读, 同时被设计用来最有效的利用以及使用内存和CPU
图中简单显示了InnoDB的存储引擎的体系架构, 从图中可见,InnoDB有多个内存块, 可以认为这些内存块组成了一个大的内存池, 负责如下工作 :
后台线程的主要作用是负责刷新内存池中的数据, 保证缓冲池中的内存缓存是最新的数据.此外将已修改的数据文件刷新到磁盘文件, 同时保证数据库发生异常的情况下InnoDB能恢复到正常运行状态
InnoDB存储引擎是多线程的模型, 因此后台有多个不同的后台线程, 负责处理不同的任务
Master Thread
主要负责将缓冲池的数据异步刷新到磁盘, 保证数据的一致性, 包括脏页的刷新, 合并插入缓冲(INSERT BUFFER), UNDO页的回收
IO Thread
在InnoDB存储引擎中大量使用了AIO(Async IO)来处理写IO请求, 这样可以大大提高数据库性能. 而IO Thread的工作主要是负责这些IO请求的回调(call back)处理, 有四种IO Thread : write, read, insert buffer, log IO Thread.
Purge Thread
事务在提交后, 其所使用的undolog可能不再需要, 因此需要PurgeThread来回收已经使用并分配的undo页.
InnoDB1.1之前 : purge操作在Master Thread中完成, InnoDB1.1开始可以独立到单独的线程中进行.
Page Cleaner Thread
将之前版本中脏页的刷新操作都放入到单独的线程中来完成
InnoDB存储引擎是基于磁盘存储的, 并将其中的记录按照页的方式进行管理. 因此可以将其视为基于磁盘的数据库系统(Disk-base Database). 在数据库系统中, 由于CPU速度与磁盘速度之间的鸿沟, 基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能.
缓冲池简单来说就是一块内存区域, 通过内存的速度来弥补磁盘速度较慢对数据库性能的影响, 在数据库中进行读取页的操作, 首先将从磁盘读到 的页存放在缓冲池中, 这个过程称为将页"FIX"在缓冲池中, 下一次再读相同的页时,首先判断该页是否在缓冲池中, 如果在,责成该页在缓冲池中被命中, 直接读取该页. 否则读取磁盘上的页
对于数据库中页的修改操作, 首先修改在缓冲池中的页, 然后再以一定的频率刷新到磁盘上.是通过一种叫做CheckPoint的机制刷新回磁盘,提高数据库的整体性能.
具体来看, 缓冲池中缓存的数据页类型有:索引页,数据页,undo页,插入缓冲(insert buffer),自适应哈希索引(adaptive hash inddex),InnoDB存储的锁信息(lock info),数据字典信息(data dictionary)等,在InnoDB 1.0.x开始, 允许有多个缓冲池实例,每个页根据哈希值平均分配到不同的缓冲池实例中,这样做的好处是减少数据库内部的资源竞争,增加数据库的并发处理能力
数据库的缓冲池是通过LRU(Latest Recent Used, 最近最少使用)算法来进行管理的. 即最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端. 当缓冲池不能存放新读取到的页时, 将首先释放LRU列表中尾端的页
在InnoDB存储引擎中, 缓冲池中页的大小默认为 16KB, 同样使用LRU算法对缓冲池进行管理,不同的是, 在InnoDB中,加入了midpoint位置. 新读取的页不直接放到LRU列表的首部, 而是放到midpoint位置,默认实在LRU列表的5/8处. midpoint之后的列表称为old列表, 之前的列表称为new列表,可以简单的理解new列表中的页都是最为活跃的热点数据
LRU用来管理已经读取的页, 但当数据库刚启动时, LRU列表是空的, 即没有任何的页, 这时页都放在Free列表中.当需要从缓冲池中分页时,首先从Free列表中查找是否有可用的空闲页, 若有则将该页从Free列表中删除,放入到LRU列表中;否则,根据LRU算法,淘汰LRU列表末尾的页,将该内存空间分配给新的页
当页从LRU列表的old部分加入到new部分时, 称此时发生的操作为page made young
缓冲池中的页还可能被分配给自适应哈希索引, Lock信息, Insert Buffer等页,而这部分不需要LRU算法维护
InnoDB从1.0.x版本开始支持压缩页的功能, 16KB的页可被压缩为1KB, 2KB, 4KB, 8KB
在LRU中的页被修改后, 称该页为脏页(dirty page), 即缓冲池中的页和磁盘上的页数据产生了不一致. 这时数据库会通过CHECKPOINT机制将脏页刷新回磁盘, 而Flush列表中的页即为脏页列表, 脏页既存在于LRU列表中, 也存在与Flush列表中. LRU列表用于管理缓冲池中页的可用性, Flush列表用来管理将页刷新回磁盘,二者互不影响
redo log buffer, InnoDB首先将重做日志信息先放入这个缓冲区, 然后按一定的频率将其刷新到重做日志文件. 一般情况下每一秒钟会将重做日志缓冲刷新到日志文件, 重做日志缓冲的默认大小为8MB
重做日志缓冲会在以下三种情况下被刷新到日志文件中:
InnoDB对内存的管理 是通过一种称为内存堆(heap)的方式进行的, 在对一些数据结构本身的内存进行分配时, 需要从额外的内存池中进行申请, 当该区域的内存不够时,会从缓冲池中申请. 例如 : 分配了缓冲池, 但是每个缓冲池中的帧缓冲还有对应的缓冲控制对象(记录了一些注入LRU,锁,等待等信息),这些内存需要从额外内存池中申请