InnoDB存储引擎体系架构

一、InnoDB体系结构

InnoDB 存储引擎有多个内存块,这些内存块组成了一个大的内存池,负责的工作如下:

  1. 维护所有进程/线程需要访问的多个内部数据结构。
  2. 缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存。
  3. 重做日志缓冲(redo log)。

    后台线程的作用:负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下 InnoDB 能恢复到正常运行状态。

二、后台线程

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

1、Master Thread

  • Master Thread 是一个非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲、undo 页的回收等。

2、IO Thread

  • 在InnoDB中大量使用了 AIO(Async IO)来处理IO请求,这样可以极大提高数据库的性能。IO Thread 的主要工作是负责这些IO请求的回调处理。
  • InnoDB 1.0 版本之前共有四个IO Thread,分别是write、read、insert buffer 、log IO Thread。
  • InnoDB 1.0.x 版本开始,read thread 和 write thread 分别增大到4个,分别使用 innodb_read_io_threads 和 innodb_wirte_io_threads 参数进行设置。
  • 查看参数:SHOW VARIABLE LIKE ‘innodb_%io_threads’\G;

3、Purge Thread

  • 事务被提交后,所使用的 undolog 日志可能不再需要,因此需要 Purge Thread 线程来回收已经使用且分配的undo页。InnoDB 1.1 版本开始,purge 操作可以独立到单独的线程中进行,可以减轻 master thread 的工作,提高CPU的使用率和提升存储引擎的性能。
  • 启用purge:innodb_purge_threads=1。
  • InnoDB 1.2 版本开始,可以启用多个 purge thread,这样做的目的是为了加快 undo 页的回收。同时由于 purge thread 需要离散的读取 undo 页,这样也能进一步利用磁盘的随机读取性能。

三、内存

1、缓冲池

  • InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。在数据库系统中,由于CPU速度和磁盘速度之间存在较大的差异,所以基于磁盘存储的数据库系统常用缓冲池技术来提高数据库的整体性能。缓冲池就是一块内存区域。
  • 在数据库中进行读取数据页的操作,首先将从磁盘读到的页放入缓冲池中,也就是将页 “FIX” 在缓冲池中。下一次要读取该页时则先从缓冲池进行读取,若缓冲池中没有才读取磁盘上的数据。
  • 对于数据库中页的修改操作,则首先是在缓冲池中修改对应的页,然后再按照一定的频率刷新到磁盘上。页从缓冲池刷新到磁盘并不是每次页发生更改时触发,而是通过 “checkpoint” 机制刷新回磁盘。通过这种方式可以提高数据库的整体性能。
  • 缓冲池大小设置:参数 innodb_buffer_pool_size 可以设置缓冲池的大小。
  • 缓冲池中缓存的数据页类型:索引页、数据页、undo 页、插入缓冲(insert buffer)、自适应哈希索引、innodb存储的锁信息、数据字典信息等。其中索引页和数据页占缓冲池的很大一部分内存。
  • 从 InnoDB 1.0.x 版本开始,可以设置多个缓冲池,将每个页根据哈希值平均分配到不同缓冲池实例中,可以减少数据库内部的竞争,增加数据库的并发处理能力。可以通过参数 “innodb_buffer_pool_instances” 来配置(可通过 “show engine innodb status” 查看缓冲池状态)。

2、内存区域管理:LRU List、Free List、Flush List

  • 数据库的缓冲池通过 LRU 算法进行管理的。当缓冲池不能存放新读取的页时,首先将 LRU 列表中尾端的页,再将新页放在 LRU 列表中前端。在 InnoDB 存储引擎中,缓冲池中页的默认大小是 16KB。
  • InnoDB 对传统的 LRU 算法做了优化,在 LRU列表中加入了 midpoint 位置。新读取的页并不是直接放入 LRU 列表的首部,而是放到 LRU 列表的 midpoint 位置。在默认配置下,midpoint 位置在 LRU 列表长度的 5/8 处,midpoint 位置可以由参数 “innodb_old_blocks_pct” 控制。把 midpoint 之前的列表称为 new 列表(热点数据),之后的列表称为 old 列表。
  • 为什么要对 LRU 算法进行改进?
    将读取的页直接放入 LRU 的首部,常见的这些操作作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部页,这些页通常来说只是在本次查询中使用,并不是活跃的热点数据。如果将页放入 LRU 列表的首部,那么非常可能将所需要的热点数据页从列表中移除,在下一次需要读取这些页时,需要再次访问磁盘,从而影响缓冲池的效率。
  • InnoDB 存储引擎还引入了另一个参数 “innodb_old_blocks_time” 来进一步管理 LRU 列表。用于表示页读取到 mid 位置后需要等待多久才会被加入到 LRU 列表的首部。
  • LRU 列表用来管理已经读取的页,当数据库启动时,列表是空的,这时页都存放在 Free 列表中。当需要从缓冲池中分页时,首先从 Free 列表中查询是否有可用的空闲页,若有则从 Free 列表中移除,放入到 LRU 列表中;否则,根据 LRU 算法淘汰 LRU 末尾的页,将该内存分配非新的页。当页从 old 部分加入到 new 部分时,此时发生的操作称作 “page made young” ;因为 “innodb_old_blocks_time” 参数的设置页没有从 old 部分加入到 new 部分时,此时发生的操作称作 “page not made young”。LRU 列表和 Free 列表的使用情况和运行情况如下所示:
  • InnoDB 存储引擎从1.0.x 版本开始支持压缩页的功能,即将原本 16KB 的页压缩为 1KB、2KB、4KB、8KB。对于非 16KB 的页,是通过 unzip_LRU 列表进行管理的,16KB 的页通过 LRU 列表进行管理。unzip_LRU 列表是怎么从缓冲池分配内存的呢?例如对需要从缓冲池中申请页为 4KB 的大小,其过程如下所示:
    1 检查 4KB 的 unzip_LRU 列表,检查是否有空闲页可用;
    2 若有,则直接使用;
    3 若没有,则检查 8KB 的unzip_LRU 列表;
    4 若能够得到空闲页,将页分成 2 个 4KB 的页,存放到 4KB 的 unzip_LRU 列表中;
    5 若不能得到空闲页,从 LRU 列表中申请一个 16KB 的页,将页分成一个 8KB 的页、2个 4KB 的页,分别存放到对应的 unzip_LRU 列表中。
    可以通过 information_schema 架构下的表 INNODB_BUFFER_PAGE_LRU 来观察 unzip_LRU 列表中的页。
  • 在 LRU 列表中被修改的页称作脏页,即缓冲池中的页和磁盘上的页的数据产生了不一致。这时数据库会通过 checkpoint 机制将脏页刷新到磁盘,而 Flush 列表中的页为脏页列表(Flush List)。脏页既存在于LRU 列表,又存在于 Flush 列表中。LRU 列表用来管理缓冲区中页的可用性,Flush 列表用来管理将页刷新回磁盘,互不影响。

3、重做日志缓冲

  • InnoDB 存储引擎的内存区域除了有缓冲池外,还有重做日志缓冲(redo log buffer)。InnoDB 存储引擎首先将重做日志信息先放入到这个缓冲区中,然后再按照一定的频率将其刷新到重做日志文件中。重做日志缓冲一般不需要设置的很大,因为一般情况下每一秒钟会将重做日志缓冲刷新到重做日志文件,因此只需要保证每秒产生的事务量在这个缓冲大小之内即可。参数 “innodb_log_buffer_sieze” 可控制,默认为 8MB。
  • 重做日志缓冲中的内容可以在下面三种情况下刷新到外部磁盘的重做日志中:
    (1)master thread 每一秒钟将重做日志缓冲刷新到重做日志文件中;
    (2)每个事务提交时会将重做日志缓冲刷新到重做日志文件中;
    (3)当重做日志缓冲池剩余空间小于 1/2 时,重做日志缓冲刷新到重做日志文件中。

4、额外的内存池

  • InnoDB 存储引擎中,对内存的管理是通过一种称为内存堆的方式进行的。在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从缓冲池中进行申请。例如:分配了缓冲池,但是每个缓冲池中的帧缓冲还有对应的缓冲控制对象,这些对象记录了一些诸如 LRU、锁、等待等信息,而这个对象的内存需要从额外的内存池中申请。因此,在申请很大的缓冲池时,也应该考虑增大这个值。

四、Checkpoint 技术

  • 若每次一个页发生变化,就将新页的版本刷新到磁盘,那么这个开销是非常大的。若热点数据集中在某几个页中,那么数据库的性能将变得非常差。如果在从缓冲池将页的新版本刷新到磁盘的过程中发生了宕机,那么数据就不能恢复了,为了避免这种情况,当前事务数据库系统普遍采用了 Write Ahead Log 策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志完成数据的恢复,可以保证事务的持久性。
  • Checkpoint 技术的目的是解决一下几个问题:
    (1)缩短数据库的恢复时间;
    (2)缓冲池不够用时,将脏页刷新到磁盘;
    (3)重做日志不可用时,刷新新页。
  • 当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint 之前的页都已经刷新回磁盘。所以数据库只需要对 Checkpoint 之后的重做日志进行恢复,这样可以大大缩短恢复的时间。当缓冲池不够用时,根据 LRU 算法会溢出最近最少使用的页,若此页为脏页,则需要强制执行 Checkpoint ,将脏页刷新回磁盘。
  • InnoDB 存储引擎是通过 LSN(Log Sequence Number) 来标记版本号,LSN是 8B 的数字,重做日志中有 LSN ,Checkpoint 中也有 LSN。
  • 两种类型的 Checkpoint :
    (1)Sharp Checkpoint:在数据库关闭时将所有的脏页刷新到磁盘中,默认的工作方式。参数 “innodb_fast_shutdow=1” 设置。 会影响数据库的可用性。
    (2)Fuzzy Checkpoint:在数据库关闭时只刷新部分页到磁盘,不会影响数据库的可用性
  • 在 InnoDB 存储引擎中可能发生以下四种 Fuzzy Checkpoint:
    (1)Master Thread Checkpoint
    差不多以每秒或每十几秒的速度从缓冲池中的脏页刷新一定比例的数据回磁盘中,这个过程是异步的,用户查询线程不会阻塞。
    (2)FLUSH_LRU_LIST Checkpoint
    InnoDB 存储引擎中需要保证 LRU 列表中有100个左右的空闲页可供使用,若没有100个可用的空闲页,那么InnoDB 存储引擎将 LRU 列表尾端的数据移除。如果这些页中有脏页,则需要进行 checkpoint ,而这些页是来自 LRU 列表的。
    (3)Async/Sync Flush Checkpoint
    在重做日志不可用的情况下,需要强制将一些页刷新回磁盘,而此时的脏页是从脏页列表中选取的。
    若将已经写入重做日志的 LSN 记为 redo_lsn,将已经刷新回磁盘最新页的 LSN 记为 checkpoint_lsn,则
    checkpoint_age=redo_lsn-checkpoint_lsn;
    async_water_mark=75%*total_redo_log_file_size;
    sync_water_mark=90%*total_redo_log_file_size;
    (a)当 checkpoint_age < async_water_mark 时,不需要刷新任何脏页到磁盘;
    (b)当 async_water_mark < checkpoint_age < sync_water_mark 时触发 Async Flush,从 Flush 列表中刷新足够的脏页回磁盘,使得 checkpoint_age < async_water_mark;
    (c) checkpoint_age > sync_water_mark 这种很少发生,除非重做日志文件设置的太小了。此时触发 Sync Flush,从 Flush 列表中刷新足够的脏页回磁盘,使得 checkpoint_age < async_water_mark。
    由此可见,Async/Sync Flush Checkpoint 是为了保证重做日志循环使用的可用性。从 MySQL 5.6 之后,这部分的刷新操作放入了单独的 Page Cleaner Thread 中,所以不会阻塞用户查询线程。
    (4)Dirty Page too much Checkpoint
    脏页的数量太多了,导致 InnoDB 存储引擎强制进行 checkpoint 。Dirty Page too much Checkpoint 的目的是保证缓冲池有足够可用的页。可通过参数 “innodb_max_dirty_pages_pct” 控制,例如:innodb_max_dirty_pages_pct=75,表示当缓冲池中的数据占据 75% 时,强制进行 checkpoint ,刷新一部分脏页到磁盘。

五、Master Thread 工作方式

InnoDB 存储引擎的主要工作都是在 Master Thread 这个单独的后台线程中完成的。

1、InnoDB 1.0.x 版本之前的 Master Thread

Master Thread 具有最高的线程优先级别。其内部由多个循环组成:主循环(loop)、后台循环(backgroup loop)、刷新循环(flush loop)、暂停循环(suspend loop)。Master Thread 会根据数据库运行的状态在这几种循环中进行切换。

(1)loop
主循环,大多数操作都是在这个循环中,包括:每秒的操作和每10秒的操作。在负载很大的情况下可能会有延迟。

每秒一次的操作包括:
a. 日志缓冲刷新到磁盘,即使这个事务还没有提交(总是发生);
b. 合并插入缓冲(可能发生,如果前一秒发生的IO次数是否小于5次,如果小于5次,则此时IO压力很小,可以执行合并插入缓冲的操作);
c. 至多刷新 100 个innodb的缓冲池中的脏页到磁盘(可能发生);
d. 如果当前没有用户活动,则切换到 backgroup loop(可能发生)。

每10秒的操作包括:
a. 刷新100个脏页到磁盘(可能发生,存储引擎会先判断过去10秒之内磁盘的IO操作是否小于200次,如果是,则刷新100个脏页到磁盘);
b. 合并至多5个插入缓冲(总是发生);
c. 将日志缓冲刷新到磁盘(总是);
d. 删除无用的 undo 页(总是,存储引擎会执行 full purge 操作,删除无用的undo页,每次最多尝试回收20个undo页);
e. 刷新 100 个或者10个脏页到磁盘(总是,存储引擎会判断缓冲池中脏页的比例,如果超过70%的脏页,则刷新100个脏页到磁盘,否则刷新10%脏页到磁盘)。

(2)backgroup loop
后台循环,若当前没有用户活动或者数据库关闭时,就会切换到这个循环。
backgroup loop 会执行以下操作:
a. 删除无用的undo页(总是);
b. 合并20个插入缓冲(总是);
c. 跳回到主循环(总是);
d. 不断刷新100个脏页直到满足条件(可能发生,跳转到 flush loop 中完成)。

(3)flush loop
若 flush loop 中也没有什么事情要做,则会切换到 suspend loop ,将 Master Thread 挂起,等待事件的发生。

(4)suspend loop

Master Thread 完整的伪代码如下所示:

void master_thread(){
		goto loop;
	loop:
	for(int i=0;i<10;i++){
		thread_sleep(1)
		do log buffer flush to disk
		if(last_once_second_ios<5)
	    	 do merge at most 5 insert buffer
	    if(buf_get_modified_ratio_pct>innodb_max_dirty_pages_pct)
			 do buffer pool flush 100 dirty page
		if(no user activity)
			 goto backgroup loop
	}
	if(last_ten_second_ios<200)
		do buffer pool flush 100 dirty page
	do merge at most 5 insert buffer
	do log buffer flush to disk
	if(buf_get_modified_ratio_pct>70%)
		do buffer pool flush 100 dirty page
	else
		buffer pool flush 10 dirty page
	goto loop
	backgroup loop:
	do full purge
	do merge 20 insert buffer
	if not idle:
	goto loop:
	else:
		goto flush loop
	flush loop:
	do buffer pool flush 100 dirty page
	if(buf_get_modified_ratio_pct>innodb_max_dirty_pages_pct)
		goto flush loop
		goto suspend loop
	suspend loop:
	suspend_thread()
	waiting event
	goto loop;
}

2、InnoDB 1.2.x 版本之前的 Master Thread

InnoDB 0.x 版本之后改进的 Master Thread。

(1)第一个改进

  • 因为 InnoDB 存储引擎对IO是有限制的,最大只会刷新100个脏页到磁盘,合并20个插入缓冲。因此 InnoDB Plugin 提供了参数 “innodb_io_capacity” ,用来表示磁盘IO的吞吐量,默认值为200。对于刷新到磁盘页的数量,会按照 “innodb_io_capacity” 的百分比来控制。
    默认规则如下:
    a. 在合并插入缓冲时,合并插入缓冲的数量为 innodb_io_capacity 的5%;
    b. 在从缓冲区刷新脏页到磁盘时,刷新脏页的数量为 innodb_io_capacity 。

(2)第二个改进

  • 参数 “innodb_max_dirty_pages_pct” 默认值的问题,在 InnoDB 1.0.x 版本之前,该值的默认值是90,表示脏页占缓冲池的90%。但是该值太大了,因为 InnoDB 存储引擎在每秒刷新缓冲池和 flush loop 时会判断这个值,如果大于 innodb_max_dirty_pages_pct 才刷新100个脏页,如果有很大的内存或者数据库服务器的压力很大,这时脏页的刷新速度反而会降低。同时,在数据库的恢复阶段可能会需要更多的时间。
  • 在 InnoDB 1.0.x 版本开始,innodb_max_dirty_pages_pct 的值被设置为75,这样既可以加快脏页的刷新的频率,也可以保证磁盘IO的负载。

(3)第三个改进

  • 参数 “innodb_adaptive_flushing” (自适应的刷新)的值影响每秒刷新脏页的数量。
  • 通过参数 “buf_flush_get_desired_flush_rate” 判断产生重做日志的速度来决定最合适的刷新脏页的数量。因此,当脏页的比例小于 “innodb_max_dirty_pages_pct” 时,也会刷新一定数量的脏页。

(4)第四个改进

  • 参数 “innodb_purge_batch_size” ,该参数可以控制每次 full purge 回收 undo 页的数量。默认值是20,并且可以动态的修改。

Master Thread 改进的的完整伪代码如下所示

void master_thread(){
		goto loop;
	loop:
	for(int i=0;i<10;i++){
		thread_sleep(1)
		do log buffer flush to disk
		if(last_once_second_ios<5% innodb_io_capacity)
	    	 do merge  5% innodb_io_capacity insert buffer
	    if(buf_get_modified_ratio_pct>innodb_max_dirty_pages_pct)
			 do buffer pool flush 100% innodb_io_capacity dirty page
		else if enable adaptive flush
			do buffer pool flush desired amount dirty page
		if(no user activity)
			 goto backgroup loop
	}
	if(last_ten_second_ios70%)
		do buffer pool flush 100% innodb_io_capacity dirty page
	else
		do buffer pool flush 10% innodb_io_capacity dirty page
	goto loop
	backgroup loop:
	do full purge
	do merge  100% innodb_io_capacity insert buffer
	if not idle:
	goto loop:
	else:
		goto flush loop
	flush loop:
	do buffer pool flush 100% innodb_io_capacity dirty page
	if(buf_get_modified_ratio_pct>innodb_max_dirty_pages_pct)
		goto flush loop
		goto suspend loop
	suspend loop:
	suspend_thread()
	waiting event
	goto loop;
}

3、InnoDB 1.2.x 版本的 Master Thread

InnoDB 1.2.x 版本再次对 Master Thread 进行了优化,Master Thread 对性能的影响起了关键性的作用。
Master Thread 的伪代码如下:

if innodb id idle
	srv_master_do_idle_tasks();//每十秒的操作
else
	srv_master_do_active_tasks();//每秒的操作

对于刷新脏页的操作,从 Master Thread 线程分离到一个单独的 Page Cleaner Thread,从而减轻了Master Thread 的工作,同时进一步提高了系统的并发性。

六、InnoDB 关键特性

InnoDB存储引擎的关键特性包括:

  • 插入缓冲(insert buffer)
  • 两次写(double write)
  • 自适应哈希索引(adaptive hash index)
  • 异步IO(async io)
  • 刷新邻接页(flush neighbor page)

1、插入缓冲

  • InnoDB存储引擎设计了 insert buffer ,对于非聚集索引的插入或更新操作,不是每一次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入;反之,则先放入一个 insert buffer 对象中。表面上数据库这个非聚集索引已经插入到页子节点,实际上并没有,只是存放在另一个位置。然后再以一定的频率和情况进行 insert buffer 和辅助索引页子节点的merge(合并)操作,这时可以将多个插入合并到一个操作中,大大提高了对于非聚集索引插入的性能。
  • insert buffer 的使用需要同时满足两个条件:
    (1)索引是辅助索引;
    (2)索引不是唯一的。
  • insert buffer 目前存在的问题:在写密集的情况下,插入缓冲会占用过多的缓冲池内存,默认最大可以占用到 1/2 的缓冲池内存。这可能会对其他操作带来一定的影响。可以通过 参数 “ibuf_pool_size_per_max_size” 设置占用的比例。
  • Change Buffer 是对 Insert Buffer 的升级。此时,InnoDB引擎可以对DML操作进行缓冲,分别是:Insert Buffer、delete Buffer、update Buffer。适用对象依然是非唯一的辅助索引。从 InnoDB 1.2.x 版本开始,可以通过参数 “innodb_change_buffer_max_size” 来控制 Change Buffer 最大使用内存的数量,默认为25,表示最多使用 1/4 的缓冲池内存空间,最大有效值是50。
  • 对一条记录进行 update 操作可分为两个过程:
    (1)将记录标记为已删除:delete Buffer
    (2)真正将记录删除:Purge Buffer
  • Insert Buffer 的内部实现:B+树,全局只有一棵 Insert Buffer B+ 树,存放在共享表空间中(ibdata1)。非叶子节点存放的是键值(search key),由 space(待插入记录所在表的表空间id)+marker(兼容老版本的 Insert Buffer)+offset(表示 页所在的偏移量) 构成,每个键值占9个字节。
  • 当一个辅助索引要插入到页时,如果这个页不在缓冲池中,那么innodb存储引擎首先要构建一个键值,接下来查询 Insert Buffer B+树,然后再将这条记录插入到 Insert Buffer B+树的叶子节点中。
  • Insert Buffer 中的记录合并到真正的辅助索引中,Merge Insert Buffer 的操作通常发生在以下几种情况:
    (1)辅助索引页被读取到缓冲池中;
    (2) Insert Buffer Bitmap 页追踪到该辅助索引页已无可用空间时;
    (3)Master Thread。

2、两次写
InnoDB存储引擎体系架构_第1张图片

  • doublewrite 可以给 InnoDB 存储引擎带来的是数据页的可靠性。当数据库发生宕机时,存储引擎正在写入到某个页中,而这个页只写了一部分,之后就发生了宕机,这种情况被称作部分写失效。在应用重做日志之前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是 doublewrite(两次写)。
  • doublewrite 由两部分组成:内存中的 doublewrite buffer ,大小为2MB;物理磁盘上共享表空间中连续的128个页,大小为2MB。
  • 在对缓冲区中的脏页进行刷新时,并不直接写入磁盘中,而是会先通过 memcpy 函数将脏页先复制到内存中的 doublewrite buffer,之后通过 doublewrite buffer 再分两次,每次以1MB顺序写入共享空间的物理磁盘上,然后马上调用 fsync 函数,同步磁盘,避免缓冲写带来的问题,这个过程中写入是连续的,开销不是很大。在完成 doublewrite 页的写入后,再将 doublewrite buffer 中的页写入 各个表空间文件中,此时的写入是离散的。

3、自适应哈希索引

  • 哈希是一种非常快的查找方法,查找时间复杂度一般是O(1)。InnoDB 存储引擎会监控对表上各索引页的查询,如果发现建立哈希索引会带来速度的提升,则建立哈希索引,称之为自适应哈希索引。通过缓冲池的B+树页构造而来,因此建立速度很快,而且不需要对整张表构建哈希索引。
  • 哈希索引只能用来搜索等值的查询,其他查询是不能使用哈希索引的。自适应哈希索引可通过参数 “innodb_adaptive_hhash_index” 来考虑是禁用或者启用此特性,默认为开启状态。

4、异步IO

  • 为了提高磁盘操作性能,当前的数据库系统都采用了异步IO的方式来处理磁盘操作。用户可以在发出一个请求后立即再发出另一个请求,当全部IO请求发送完毕后,等待所有IO操作的完成。
  • AIO 的另一个优势是可以进行 IO merge 操作,将多个IO合并成一个IO。
  • 从 InnoDB 1.1.x 版本开始,提供了内核级别AIO的支持,称为 Native AIO。可用过参数 “innodb_use_native_aio” 来设置的是否启用。在 InnoDB 存储引擎中,read ahead 方式的读取都是通过AIO完成,脏页的刷新,即磁盘的写入操作全由AIO完成。

5、刷新邻接页

  • 工作原理:当刷新一个脏页时, InnoDB 存储引擎会检测该页所在区的所有页,如果是脏页,那么一起进行刷新。适用于传统的机械硬盘。

七、 InnoDB 存储引擎的启动、关闭与恢复

  • 在关闭时,参数 “innodb_fast_shutdown” 影响着表的存储引擎为 InnoDB 的行为。参数的取值可以为0、1、2,默认为1。
    (1)0:表示在MySQL数据库关闭时, InnoDB 需要完成所有的 full purge 和 merge insert buffer,并且将所有的脏页刷新回磁盘。这个过程很耗时。
    (2)1:默认值,表示不需要完成上述的 full purge 和 merge insert buffer 操作,但是在缓冲池中的一些脏页还是会刷新回磁盘。
    (3)2:表示不完成 full purge 和 merge insert buffer 操作,也不会将缓冲池中的脏页刷新回磁盘,而是将日志都写入日志文件。这样不会有任何事务的丢失,但是下次MySQL数据库启动时,会进行恢复操作。
  • 参数 “innodb_force_recovery” 影响着 InnoDB 存储引擎恢复的状况。该参数默认值为0,代表当发生需要恢复时,进行所有的恢复操作,当不能进行有效恢复时,MySQL 数据库可能会发生宕机,并把错误写入错误日志中。但是在某些情况下,不需要进行完整的数据恢复操作,用户知道怎么恢复。
  • 参数 “innodb_force_recovery” 可以设置6个非零值:1-6,大的数字表示 包含了前面所有小数字表示的影响。参数值大于0时,用户不可以对表进行DML操作。
    (1)1:忽略检查到的 corrupt 页。
    (2)2:阻止master thread 线程的运行。
    (3)3:不进行事务的回滚操作。
    (4)4:不进行插入缓冲的合并操作。
    (5)5:不查看撤销日志(undo log),存储引擎会将未提交事务视为已提交。
    (6)6:不进行前滚的操作。

你可能感兴趣的:(mysql,innodb存储引擎体系架构,存储引擎,数据库)