InnoDB体系架构
InnoDB中主要包含后台线程和内存,其中:
- 后台线程的作用是负责刷新内存中的数据,同时保证数据库发生异常时可以回滚到正常运行状态。
- 内存的作用是用于缓存磁盘上的数据便于读取。
后台线程
Master Thread
将缓冲池中的数据异步刷新到磁盘中,保证数据的一致性,包括脏页的刷新、合并插入缓冲、undo页的回收。
IO Thread
负责AIO请求的回调处理,共有4个IO Thread分别是write、read、insert buffer和log Thread。
Purge Thread
事务被提交后,使用的undo log可能就不再需要了,所以需要通过purge thread来回收已经使用并分配的undo页。
Page Cleaner Thread
该线程是InnoDB1.2版本引入的,主要负责脏页的数据刷新。减轻原Master Thread的工作对于用户查询线程的堵塞,提高InnoDB存储引擎的性能。
内存
缓存池
- 缓冲池简单的理解就是一块内存区域,通过内存的速度来弥补磁盘读写速度对数据库性能的影响。
- 对于数据库中读取页的操作,首先会将从磁盘中读到的页放入缓冲池中,下次再读相同页时会先判断该页是否在缓冲池中,如果在缓冲池中则直接读取该页,否则读取磁盘上的页。
- 对于数据库中页的修改操作,首先修改缓存池中的页,然后再以一定的频率刷新到磁盘。(注意:通过CheckPoint机制刷新回磁盘)
- 缓存池中缓存的数据有:索引页、数据页、undo页、插入缓冲、自适应哈希索引、InnoDB存储的锁信息、数据字典信息等。
- 允许有多个缓冲池实例。(每个页根据哈希值平均分配到不同缓冲池实例中,目的是减少数据库内部的资源竞争,增加数据库的并发处理能力)
如何管理内存
LRU List
LRU列表用于管理已经读取到的页,将最频繁使用的页放在LRU列表的前端,最少使用的页放在LRU列表的尾端。新读取到的页放到LRU列表的midpoint位置,midpoint之后为old列表,midpoint之前为new列表。通过innodb_old_blocks_times参数可以设置读取页到mid位置后多久加入LRU列表的前端。
Free List
数据库刚启动时LRU列表是空的,所有空闲页都存在Free列表中。当需要从缓存池中分页,首先回从Free列表查看是否有可用的空闲页,如果有则从Free列表中删除并放入LRU列表中。否则,根据LRU算法淘汰列表尾端的页,将该内存空间分配给新的页。
unzip LRU List
InnoDB存储引擎支持压缩页的功能,将16KB的页压缩为1KB、2KB、4KB和8KB。对于非16KB的页,存放在unzip LRU列表进行管理。LRU列表包含于unzip LRU列表的页。
unzip LRU列表从缓存池中申请4KB页的过程:
- 检查4KB的unzip_LRU列表,是否有可用的空闲也;
- 如果有,则直接使用;
- 否则,检查8KB的unzip LRU列表;
- 如果有空闲页,则将8KB页分成2个4KB页,存放在4KB的unzip_LRU列表;
- 如果没有空闲页,从LRU列表申请一个16KB的页,将页分为1个8KB的页、2个4KB的页,分别存放在对应的unzip LRU列表中。
Flush List
LRU列表中被修改的页,称之为脏页(dirty page),即缓冲池中的页和磁盘上页的数据不一致。这时数据库会通过CheckPoint机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。脏页既存在于LRU列表中,也存在于Flush列表中。LRU列表用来管理缓冲池中页的可用性,Flush列表用来管理将页刷新回磁盘。
重做日志缓冲
重做日志首先会存放到重做日志缓冲,然后按照一定频率将其刷新到重做日志文件。重做日志缓冲一般不需要设置很大,默认大小为8M。
在下列三种情况下会将重做日志缓冲刷新到外部磁盘的重做日志文件中:
- Master Thread每一秒将重做日志缓冲刷新到重做日志文件;
- 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
- 当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件。
额外内存池
数据结构本身的内存是从额外内存池中申请的,当额外缓冲池中内存不够时,会从缓冲池中申请。
|