在上一篇博客InnoDB体系架构 内存中,介绍了InnoDB存储引擎的内存结构和设计,这里就来介绍Checkpoint技术。前面我们提到过数据库会通过Checkpoint机制将脏页刷新回磁盘,该技术主要用于解决一下几个问题:
1.缩短数据库的恢复时间;
2.缓冲池不够用时,将脏页刷新到磁盘;
3.重做日志不可用时,刷新脏页。
当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘,所以数据库只需要对Checkpoint之后的重做日志进行恢复,这样能够缩短恢复的时间。此外当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页那么需要强制执行Checkpoint,将脏页的新版本刷回磁盘。
在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。
在此处我主要介绍后面三种,FLUSH_LRU_LIST Checkpoint是因为InnoDB存储引擎需要保证LRU列表中需要有差不多100个空闲页可供使用,在InnoDB1.1.x版本之前,需要检查LRU列表中是否有足够的可用空间操作发生在用户查询线程中,显然这会阻塞用户的查询操作。倘若没有100个可用空闲页,那么InnoDB存储引擎会将LRU列表尾端的页移除,如果这些页中有脏页就要进行Checkpoint,而这些页来自于LRU列表所以称为FLUSH_LRU_LIST Checkpoint。从MySQL5.6版本开始,这个检查被放在了一个单独的Page Cleaner线程中执行,并且可以通过参数innode_lru_scan_depth控制LRU列表中可用页的数量,默认值为1024.
Async/Sync Flush Checkpoint指的是重做日志文件不可用的情况,此时需要强制将一些页刷新回磁盘,而此时脏页是从脏页列表中选取的。将已经写入到重做日志的LSN(Log Sequence Number,用来标记版本)记为redo_lsn,将已经刷新回磁盘最新页的LSN记为checkpoint_lsn则有:checkpoint_age = rso_lsn - checkpoint_lsn,在定义以下的变量:
async_water_mark = 0.75 * total_redo_log_file_size
sync_water_mark = 0.9 * total_redo_log_file_size则有当checkpoint_age<async_water_mark是不需要刷新任何脏页到磁盘;
当async_water_mark<checkpoint_age<sync_water_mark时触发Async Flush,从Flush列表中刷新足够的脏页回磁盘使得刷新后满足checkpoint_age<async_water_mark;当checkpoint_age>sync_water_mark时,触发Sync Flush,从Flush列表中刷新足够的脏页回磁盘,使得刷新后满足checkpoint_age<async_water_mark。由此可见Async/Sync Flush Checkpoint是为了保证重做日志的循环使用的可能性。
Dirty Page too much Checkpoint是脏页太多,导致InnoDB存储引擎强制进行Checkpoint,当缓冲池中脏页的数量占据75%时,会发生该类型的Checkpoint。