InnoDB的体系架构
InnoDB存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池,可以负责以下工作
- 维护所有进程/线程需要访问的多个内部数据结构。
- 缓存磁盘上面的数据,方便快速地读取,同时在磁盘文件的修改之前在这里缓存
- 重做日志缓存
- ········ 其中后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外将以修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB能恢复到正常运行状态。
![R@066V20]6LMLR~BGG187SL.png](p3-juejin.byteimg.com/tos-cn-i-k3…?)
后台线程
InnoDB存储引擎是多线程的模型,因为后台有多个不同的后台线程,负责处理不同的任务
1.Master Thread
Master Thread是一个核心的线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷野、合并插入缓冲(INSERT BUFFER)、UNDO页的回收
2.IO Thread
InnoDB存储引擎中大量使用了AIO(Async IO)来处理写IO请求,这样可以提高数据库的性能。而IO Thread的工作主要是负责这些IO请求的回调(call back)
3.Purge Thread
事务在提交以后,其使用的undolog可能不在需要,因此需要PurgeThread来回收已经使用并分配的undo页。在1.1版本之前,purge操作仅在Master Thread中完成。从1.1以后,purge操作可以独立到单独的线程中进行,以此来减轻master的工作,提高cpu的使用率以及提升存储引擎的性能。从1.2开始,InnoDB支持多个Purge Thread,目的是为了能进一步加快undo页的回收。同时由于Purge Thread需要离散地读取undo页,这样也能更一步利用磁盘的随机读取性能。
4.Page Cleaner Thread
将脏页的刷新操作都放入单独的线程中完成,目的是减轻原Master的工作及对于用户查询线程的阻塞。
内存
1.缓冲池
- InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。由于CPU速度与磁盘速度直接的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的性能。
- 缓冲池简单来说就是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。在数据库进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程成为将页“fix”在缓冲池中。下一次再读取相同的页时,首先判断该页是否在缓冲池中。
- 对于数据库中页的修改操作,则首先修改的是在缓冲池中的页,然后触发Checkpoint的机制刷新回磁盘,这样也是为了提高数据库的整体性能。
- 缓冲池中缓存的数据也类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引、InnoDB存储的锁信息、数据字典信息等。
- InnoDB允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。这样可以减少数据库内部的资源竞争,增加数据库的并发处理能力。
![ZP@3A8~D8%S}IB5ASYN_{2.png
2.LRU List、Free List和Flush List
- 数据库中的缓冲池是通过LRU(最近最少使用)算法来进行管理的。即最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。缓冲池中页的大小默认为16KB,InnoDB对LRU算法做了一些优化,对LRU列表中还加入了midpoint位置。对于新读取到的页,并不是直接放到LRU列表的首部,而是放入LRU列表的midpoint处。默认情况下midpoint为5/8,可由参数innodb_old_blocks_pct控制。
- innodb中把midpoint之后的列表成为old列表,之前的列表称作为new表。可以简单的将new列表中的页都是最为活跃的热点数据。这样做的原因是,为了防止类似像作为索引或数据的扫描操作,需要访问表中的很多页,而这些页通常来说仅仅是这次查询操作中需要,并不是活跃的热点数据。如果这些页直接放入到LRU的首部,就非常有可能将所需要的热点数据移除。
- 为了解决这个问题,引入了innodb_old_blocks_time,用于表示页读取到mid位置后需要等待多久才会被加入到LRU列表的热端。
- LRU列表用来管理已经读取的页。数据库刚启动的时候,LRU的列表是空的,这时页都存放在Free列表中。当选需要从缓冲池中分页时,首先要从Free列表中查找是否有可用的空闲页。
- InnoDB支持压缩页的功能。将原本16KB的页压缩为1KB、2KB、4KB和8KB。对于非16KB的页,是通过unzip_LRU列表进行管理的。
- 在LRU列表中的页被修改后,称该页为脏页,即缓冲池中的页和磁盘上的页的数据产生了不一致。这时数据库会通过Checkpoint机制将脏页刷新回磁盘,而flush列表中的页即为脏页列表。脏页也存在与LRU列表中。
重做日志缓冲
内存区域除了有缓冲区以后,还有重做日志缓冲(redo log buffer)。innodb首先将重做日志信息先放入到这个缓冲区,然后按一定频率刷新到重做日志文件。重做日志在下面三种情况下会将缓冲中的内容刷新到外部磁盘的重做日志文件中。
- Master Thread每一秒将重做日志缓冲刷新到重做日志文件
- 每个事务提交时
- 当重做日志缓冲池剩余空间小于1/2时
额外的内存池
在innodb中,对内存的管理时通过一种称作为内存堆的方式进行的。在堆一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请。
Checkpoint技术
- 为了避免发生数据丢失的问题,当前事务数据库系统普遍都采用了Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复。但是,如果完全需要通过重做日志来恢复整个数据库系统中的数据,需要两个前提条件:1.缓冲池可以缓存数据库中所有的数据2.重做日志可以无限增大。但是这两个条件都要求太高。
- 因此Checkpoint技术的目的就是解决以后几个问题:
- 缩短数据库的恢复时间
- 缓冲池不够用时,将脏页刷新到磁盘
- 重做日志不可用时,刷新脏页
- 当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。故只需对checkpoint之后的重做日志进行恢复。
- Checkpoint分为两种
- Sharp Checkpoint
- Fuzzy Checkpoint
- Sharp Checkpoint发生在数据库关闭时将所有的脏页都刷新回磁盘
- Fuzzy Checkpoint进行页的刷新就是刷新一部分的脏页。innodb中可能发生以下几种情况的Fuzzy Checkpoint。
- Master Thread Checkpoint 差不多以每秒或者每十秒的速度从缓冲池的脏页刷新一定比例的页回磁盘。这个过程是异步的,可以进行其他操作,用户查询线程不会阻塞
- FLUSH_LRU_LIST Checkpoint 是因为innodb需要保证LRU列表中需要有差不多100个空闲页可供使用
- Async/Sync Flush Checkpoint 指重做日志不可用的情况下,需要强制将一些页刷新回磁盘,此时的脏页是从脏页列表中选取的,是为了保证重做日志的循环使用的可用性。这部分的刷新此操作放入了单独的Page Cleaner Thread中,故不会阻塞用户查询线程。
- Dirty Page too much Checkpoint 当缓冲池中脏页的数据占据75%时,强制进行Checkpoint。