MySQL

MySQL笔记三:InnoDB存储引擎

1.Checkpoint技术

如果在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么数据就不能恢复了。为了避免发生数据丢失的问题,当前事务数据库系统普遍都采用了Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复。这也是事务ACID中D(Durability持久性)的要求。

Checkpoint技术的目的是解决以下几个问题:

  • 缩短数据库的恢复时间
  • 缓冲池不够用时,将脏页刷新到磁盘
  • 重做日志不可用时,刷新脏页

当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。故数据库只需要对 Checkpoint 后的重做日志进行恢复。这样就大大缩短了恢复的时间。

此外,当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。

对于InnoDB存储引擎而言,其是通过LSN(Log Sequence Number)来标记版本的。LSN是8字节的数字,其单位是字节。每个页有LSN,重做日志中也有LSN,Checkpoint也有LSN。

在InnoDB存储引擎内部,有两种Checkpoint,分别为Sharp Checkpoint、Fuzzy Checkpoint 。Sharp Checkpoint 发生在数据库关闭时将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数innodb_fast_shutdown=1.而在InnoDB存储引擎内部使用Fuzzy Checkpoint 进行页的刷新,即只刷新一部分脏页,而不是刷新所有的脏页回磁盘。

在InnoDB存储引擎中可能发生如下几种情况的Fuzzy Checkpoint :

  • Master Thread Checkpoint
  • FLUSH_LRU_LIST Checkpoint
  • Async/Sync Flush Checkpoint
  • Dirty Page too much Checkpoint

对于 Master Thread 中发生的 Checkpoint ,差不多以每秒或每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘。这个过程是异步的,即此时InnoDB存储引擎可以进行其他的操作,用户查询线程不会阻塞。

FLUSH_LRU_LIST Checkpoint 是因为InnoDB存储引擎需要保证LRU列表中需要足够空闲页可用。Page Cleaner线程会检查LRU列表中是否有足够的可用空间,倘若没有,那么InnoDB存储引擎会将LRU列表尾端的页移除。如果这些页中有脏页,那么需要进行Checkpoint,show variables like ‘innodb_lru_san_depth’,该值默认为1024.

Async/Sync Flush Checkpoint指的是重做日志文件不可用的情况,这时需要强制将一些页刷新回磁盘,而此时脏页是从脏页列表中选取的。

Async/Sync Flush Checkpoint 是为了保证重做日志的循环使用的可用性,这部分的刷新操作放入到了单独的Page Cleaner Thread中,故不会阻塞用户查询线程。

Dirty Page too much Checkpoint ,脏页数量太多,导致InnoDB存储引擎强制进行Checkpoint,其目的总的来说还是为了保证缓冲池中有足够可用的页,show variables like ‘innodb_max_dirty_pct’,默认为75,当缓冲池中脏页的数量占据75%时,强制进行Checkpoint,刷新一部分的脏页到磁盘。

2.Master Thread工作方式

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

Master Thread 具有最高的线程优先级别,其内部由多个循环组成:主循环(loop)、后台循环(backgroup loop)、刷新循环(flush loop)、暂停循环(suspend loop)。

Loop为主循环,因为大多数的操作是在这个循环中,其中有两大部分的操作—每秒钟的操作和每10秒的操作。

每秒一次的操作包括:

  • 日志缓冲刷新到磁盘,即使这个事务还没有提交(总是)
  • 合并插入缓冲(可能)
  • 至多刷新100个InnoDB的缓冲池中的脏页到磁盘(可能)
  • 如果当前没有用户活动,则切换到background loop(可能)

即使某个事务还没有提交,InnoDB存储引擎仍然每秒会将重做日志缓冲中的内容刷新到重做日志文件。这一点是必须要知道的,因为这可以很好地解释为什么再大的事务提交的时间也是很短的。

合并插入缓冲(Insert Buffer)并不是每秒都会发生的。InnoDB存储引擎会判断当前一秒内发生的IO次数是否小于5次,如果小于5次,InnoDB认为当前的IO压力很小,可以执行合并插入缓冲的操作。

刷新100个脏页也不是每秒都会发生的。InnoDB存储引擎通过判断当前缓冲池中脏页的比例是否超过了配置文件中innodb_max_dirty_pages_pct这个参数,如果超过了这个阈值,InnoDB存储引擎认为需要做磁盘同步的操作,将100个脏页写入磁盘中。

每10秒的操作:

  • 刷新100个脏页到磁盘(可能的情况下)
  • 合并至多5个插入缓冲(总是)
  • 将日志缓冲刷新到磁盘(总是)
  • 删除无用的Undo页(总是)
  • 刷新100个或者10个脏页到磁盘(总是)

若当前没有用户活动(数据库空闲时)或者数据库关闭(shutdown),就会切换到background loop。 background loop 会执行以下操作:

  • 删除无用的Undo页(总是)
  • 合并20个插入缓冲(总是)
  • 跳回到主循环(总是)
  • 不断刷新100个页直到符合条件(可能,跳转到flush loop中完成)

InnoDB存储引擎对于IO其实是有限制的,当固态硬盘出现时,这种规定在很大程度上限制了InnoDB存储引擎对磁盘IO的性能,尤其是写入性能。

InnoDB Plugin提供了参数innodb_io_capacity,用来表示磁盘IO的吞吐量,默认值为200,对于刷新到磁盘页的数量,会按照 innodb_io_capacity 的百分比来进行控制,规则如下:

  • 在合并插入缓冲时,合并插入缓冲的数量为 innodb_io_capacity 值的5%
  • 在从缓冲区刷新脏页时,刷新脏页的数量为 innodb_io_capacity

3. InnoDB关键特性

  • 插入缓冲(Insert Buffer)
  • 两次写(Double Write)
  • 自适应哈希索引(Adaptive Hash Index)
  • 异步IO(Async IO)
  • 刷新邻接页(Flush Neighbor Page)

发表评论