InnoDB是事务安全的存储引擎,架构设计上类似于Oracle数据库。其特点是支持ACID,行锁设计,支持MVCC,支持外键,提供一致性非锁定读等。
InnoDB体系结构
InnoDB存储引擎主要包括内存池和后台进程。
InnoDB存储引擎有多个内存块,这些内存块组成了更大的内存池,负责如下工作:
1.维护所有进程/线程需要访问的多个内部数据结构;
2.缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存;
3.重做日志(redo log)缓冲;等等;
后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最新的数据。此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB能恢复到正常运行状态。
后台线程
InnoDB存储引擎后台有多个线程分别处理不同的任务。
Master Thread
Master Thread 是一个核心线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲(INSERT BUFFER)、回滚页(UNDO PAGE)的回收等。
Master Thread具有最高的线程优先级,其内部由多个循环组成;
IO Thread
InnoDB存储引擎使用了大量的AIO(Async IO)来处理IO请求,提高了数据库的性能;
IO Thread主要负责这些IO请求的回调(call back)处理;
InnoDB 1.0版本之前共有4个IO Thread,分别是write,read,insert buffer和log;
Purge Thread
事务被提交后,其所使用的undolog可能不再需要,因此需要Purge Thread来回收已经使用并分配的undo页;
Page Cleaner Thread
将之前版本中脏页的刷新操作都放入到单独的线程中来完成,目的是为了减轻原Master Thread的工作及对于用户查询线程的阻塞,提高InnoDB存储引擎的性能;
内存
缓冲池
InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。
因此,可以将它视为基于磁盘的数据库系统;
由于CPU和磁盘在速度上的差异,InnoDB需要使用缓冲池来提高数据库的性能;
缓冲池简单来说,就是一块内存区域,通过内存的速度来弥补磁盘访问速度慢对性能的影响;在数据库中进行读取页的操作时,首先将从磁盘中读到的页放在缓冲池中,这个过程被称为将页"FIX"到缓冲池中;等到下一次读取相同的页时,首先判断该页是否在缓冲池中;若在,称该页在缓冲池中被命中,直接读取该页;否则,读取磁盘上的页;
如果要修改页,首先先修改在缓冲池中的页,然后以一定的频率刷新到磁盘上。页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发的,而是通过一种称为Checkpoint的机制刷新回磁盘额度;
这也是为了提高性能;
所以,缓冲池的大小直接影响到数据库的整体性能;InnoDB可以通过innodb_buffer_size参数来配置缓冲池的大小;
缓冲池中缓存的数据页类型有:索引页,数据页,undo页,插入缓冲,自适应哈希索引,InnoDB存储的锁信息,数据字典信息等。
不能简单的认为,缓冲池只是缓存索引页和数据页,它们只是占缓冲池很大的一部分;
InnoDB允许有多个缓冲池实例。每个页根据哈希值平均分配到不同的缓冲池实例中。这样做的好处是减少数据库内部的资源竞争,增加数据库的并发处理能力;
缓冲池是通过LRU(最近最少使用)算法来对页进行管理的,即最频繁使用的页在LRU列表的前端,最少使用的页在LRU列表的尾端。当缓冲池不能存放最新读取到的页时,将首先释放LRU列表中尾端的页;
缓冲池中页的大小默认是16KB;当然,LRU列表中还加入了midpoint位置,新读取到的页,并不是直接放入到LRU列表的首部,而是放入到LRU列表的midpoint位置。
这个算法在InnoDB存储引擎下被称为midpoint insertion strategy;默认情况下,是在LRU列表的5/8处;
把midpoint之后的列表称为old列表,之前的列表称为new列表;new列表中的页都是活跃;
那为什么不直接把最新的页放在LRU列表的首部呢?如果直接放在首部,那么某些SQL操作可能会使缓冲池中的页被刷新出,从而影响缓冲池的效率;常见的这种操作为索引或数据的扫描操作,这类操作需要访问表中的许多页,甚至是全部的页,而这些页通常来说又仅在这次查询操作中需要,并不是活跃的数据页;如果把页放在LRU列表的首部,那么非常可能将所需要的热点数据页从LRU列表中移除,下一次访问就得读取磁盘了;
为了解决这个问题,有个innodb_old_blocks_time用于表示页被放在mid位置后需要等待多久才会被加入到LRU列表的热端;
重做日志缓冲
InnoDB存储引擎首先将重做日志信息放入这个缓冲区,然后按照一定的频率将其刷新到重做日志文件。
重做日志缓冲一般不需要设置的很大,因为一般情况下每一秒会将重做日志缓冲刷新到日志文件,因此用户只需要保证每秒产生的事务量在这个缓冲大小之内即可;默认是8MB,可通过innodb_log_buffer_size控制;
重做日志在下列三种情况下会将重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中:、
1.Master Thread每一秒将重做日志缓冲刷新到重做日志文件;
2.每个事务提交时会将重做日志缓冲刷新到重做日志文件;
3.当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件;
额外的内存池
Mark.需要补充;