InnoDB(2.3):Master Thread

Master Thread工作方式

InnoDB的主要工作都是在一个单独的后台线程Master Thread中完成的。

InnoDB 1.0.x版本之前的工作方式

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

Loop循环

Loop循环被称为是主循环,因为大多数的操作都是在这个循环里面中的,其中这里面有两大部分的操作,分别如下

  1. 每秒钟的操作
  2. 每十秒的操作

伪代码如下

void master_thread(){
	loop: //loop循环
	for(int i = 0;i < 10;i++){
		do thing once per seond //每一秒执行的操作
		sleep 1 second if necessary //睡眠一秒钟
	}
	do things once per ten seconds //每十秒钟执行的操作
 	goto loop;
}

可以看到,loop循环中来进行每一秒和每十秒的操作是通过sleep来实现的,这就意味着在负载量大的场景下,所谓的每一秒或每10秒的操作是不精确的,不过在InnoDB源代码中还通过了其他的方法来尽量保证这个频率

每一秒的操作

每一秒的操作包括下面这些

  1. 重做日志(Redo页)刷新到磁盘上,即使这个事务还没有提交(总是执行)
  2. 合并插入缓冲,即Insert buffer(总是执行,不过是判断操作总是执行,合并插入并不是)
  3. 至多刷新100个InnoDB的缓冲池中的脏页到磁盘(可能执行)
  4. 如果当前没有用户活动,则切换到background loop(可能执行)

即使某个事务还没有提交,InnoDB存储引擎仍然会每秒会将重做日志缓冲中的内容刷新到重做日志,为了实现ACID的持久性,这也是为什么再大的事务,它的提交时间也是很短的。

合并插入缓冲(Insert buffer,插入的时候并不是直接刷新进磁盘,也是要先进入缓冲池)则并不是每秒都发生的,不过是每秒都会去进行判断,当前一秒内发生的IO次数是否小于5次,如果少于5次,才会进行IO操作(因为InnoDB认为少于5次的IO操作的压力会很小,可以执行合并插入缓冲的操作)

同样地,刷新100个脏页也不是每秒都会去发生,InnoDB存储引擎通过判断当前缓冲池中的脏页比例(buf_get_modified_ratio_pct)是否超过了Innodb中规定的脏页比例(dirty_pages_pct参数,默认为90,这是旧版本参数,新版本为InnoDB_max_dirty_pages_pct),如果超过了这个阈值,InnoDB存储引擎才会认为此时需要将磁盘同步,将最多100个脏页写入磁盘中。

最后地当前要判断当前用户有没有活动,没有活动就会切换到background loop循环中。

每十秒的操作

每十秒的操作包括下面这些

  1. 刷新100个脏页到磁盘(可能执行)
  2. 合并至多5个插入缓冲(总是执行)
  3. 将重做日志缓冲刷新到磁盘(总是执行)
  4. 删除无用的Undo页(总是执行)
  5. 刷新100个或者10个脏页到磁盘(总是执行)

InnoDB会先去判断10秒以内的IO操作是否少于200次,如果少于200次,InnoDB引擎才会觉得IO压力比较少,才会执行刷新最多100个脏页到磁盘中。

接着InnoDB会去合并插入缓冲,不同于前面的每一秒的合并插入缓冲操作(需要去判断IO次数),而是每个阶段都会进行,即每个10秒都会进行(即使没有插入缓冲)

之后,InnoDB会再一次将重做日志刷新到磁盘的操作。这个和每一秒执行的刷新重做日志是一样的

接着InnnoDB存储引擎会下一步执行full purge操作,即删除无用的Undo页(Undo页是指原来未改变时的内容,也就是旧版本的行数据),对表进行updayte、delete这类操作时,对应的行会被标记为删除,但是因为一次性读的关系,是需要保持这些行版本的信息的**(一次性读是针对事务的,比如一个事务对表进行修改,这个事务还没有提交,此时并发了另一个事务也要访问该表,由于前一个事务还没有提交,但是已经重做日志已经开始记录了,那么并发的另一个事务就要从Undo页中去读取,保证数据的一致性,即没有提交的修改不算有效的修改)**。在full purge操作过程中,InnoDB存储引擎会判断事务系统中以被删除的行是否真的可以删除(即判断数据是否真的已经不需要了),如果真的可以删除,InnoDB就会删除保存了旧数据的undo页(已经完全不需要了),但如果不可以删除,比如有时候可能有一些查询操作会需要到之前版本的Undo信息。

最后InnoDB存储引擎会判断缓冲池中脏页的比例,通过参数buf_get_modified_ratio_pct去判断,如果超过70%的脏页,则刷新100个脏页到磁盘,如果脏页的比例低于70%,则只刷新10个的脏页到磁盘。

background loop

前面提到过,每一秒的操作里面,若当前没有用户访问,则会切换到background loop,其实当数据库关闭的时候也是会切换到background loop的。

background loop会执行以下操作

  1. 删除无用的Undo页(总是执行)
  2. 合并20个插入缓冲(总是执行)
  3. 跳回到master loop(总是执行)
  4. 不断刷新100个页直到符合条件(可能执行,切换到flush loop中完成)

如果flush loop中没有什么事情可做,InnoDB存储引擎会切换到suspend_loop,将Master Thread挂起,等待事情发生,假如用户只是启用了InnoDB存储引擎,却没有使用任何InnoDB存储引擎的表,那么Master Thread总是处于挂起的状态。

InnoDB 1.2.x版本之前的Master Thread

1.0.x版本之前对于IO是有次数限定的,就好像前面提到的,最多的只有background loop那里可以刷新100个脏页然后合并20个插入缓冲,但是,硬件的发展也很快(现在SSD固态磁盘),写入速度越来越快,这样的规则只会降低InnoDB存储引擎对硬盘的使用效率。

在写入密集型应用程序中,每秒可能产生的脏页数大于100个,产生的插入缓冲大于20个,那么Master Thread似乎会忙不过来,或者说效率很慢,当宕机的需要进行数据恢复的时候,由于很多数据没有恢复到磁盘,只能根据大量的Redo页去进行,导致恢复时间可能需要很久,尤其是对于Insert buffer来说

因此从1.0.x版本开始,InnoDB PLUGIN提供了参数innodb_io_capacity,用来表示磁盘IO的吞吐量,默认值为200。对于刷新到磁盘页的数量,会按照innodb_io_capacity的百分比来进行控制,规则如下所示

  1. 在合并插入缓冲时,合并插入缓冲的数量为innodb_io_capacity的5%(不是之前限制的5或20条)
  2. 在从缓冲区刷新脏页时,刷新脏页的数量为innodb_io_capacity。(不是之前限制的最多100条)

所以当拥有了更好的存储设备时,完全可以将innodb_io_capacity的值调得更高一些,直到符号磁盘IO得吞吐量为止。

第二个优化就是调整了参数innodb_max_dirty_pages_pct默认值,在InnoDB 1.0.X版本之前,该值的默认为90,意味着脏页的数量占缓冲池所有页的90%参进行刷新,这个值太大了,如果此时数据库服务器的压力很大,这是刷新脏页的速度会降低,同样,在数据恢复阶段也会耗费更多的时间。所以,innodb_max_dirty_pages_pct默认值变为了75,加快了刷新页的频率,又能保证磁盘IO的负载(这个值好像是通过测试出来的,Google最后得出了80是最优的)

第三个优化就是带来了一个名为innodb_adaptive_flushing(自适应刷新)的参数,该值会影响每秒刷新脏页的数量,原来的刷新规则是:脏页在缓冲池中所占的比例不小于innodb_max_dirty_pages_pct时,就不会刷新脏页,如果超过,就刷新100个脏页(1.0.x版本的 规则),新版引入了innodb_adaptive_flushing参数,也引入了一个名为buf_flush_get_desired_flush_rate来判断需要刷新脏页的最合适数量(而不是固定100页),他的原理是通过判断产生重做日志(redo log)来决定最适合的脏页数量的,因此,当脏页比例小于innodb_max_dirty_pages_pct参数时,会刷新适合的脏页数量,不再是固定的100页。

第四个优化就是又引入了一个名为innodb_purege_batch_size的参数,该参数可以控制每次full purge操作回收的undo页的数量,可以动态对其进行修改。

InnoDB 1.2.x版本的Master Thread

InnoDB1.2.X版本只是提高了并发性,通过将MasterThread的工作分离到一个单独的Page Cleaner Thread去执行,从而减轻了Master Thread的工作,进一步提高了系统的并发性。

它的伪代码如下

if InnoDB is idle
	srv_master_do_idle_tasks(); //分离到一个Page Cleaner Thread执行每10秒的操作
ELSE 
	srv_master_do_active_asks(); //分离到一个Page Cleaner Thread执行每一秒的操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值