在LRU列表中的页被修改后,称该页为脏页,即缓冲池中的页和磁盘上的页的数据产生了不一致。这是数据库会通过CHECKPOINT机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。注意:脏页即存在于LRU列表中,也存在于Flush列表中。LRU列表管理缓冲池中页的可用性,Flush列表用来管理页刷新回磁盘,二者不影响。
重做日志缓冲InnoDB存储引擎首先将重做日志信息放入重做日志缓冲区,然后按照一定的频率将其刷入到重做日志文件。由参数innodb_log_buffer_size控制,默认为8M。
重做日志在下面三种情况下会把重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中。
Master Thread每一秒将重做日志缓冲刷新到重做日志文件。
每个事物提交时会将重做日志缓冲刷新到重做日志文件。
当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件。
Checkpoint技术如果使用Update或Delete操作,改变了页中的记录,那么此时页是脏的,即缓冲池中的页的版本比磁盘的新。数据库需要将新版本的数据从缓冲池刷新到磁盘。
但是不能每一次变化,都将新页的数据刷新到磁盘。一方面开销太大,再就是如果在刷新过程中发生了宕机,那么数据不能恢复,为了避免发生数据丢失的问题,数据库普遍采用Write Ahead Log策略,即当事务做日志提交时,先写重做日志,再修改页。如果发生宕机,通过重做日志文件来完成数据的恢复。
如果缓冲池缓存数据库中所有的数据,而且重做日志能够无线的增大,那么不需要将缓冲池中的新版本刷新回磁盘。因为发生宕机的时候通过重做日志文件就可以恢复整个数据库系统中的数据到宕机发生的时刻。但是这需要两个条件:1.缓冲池可以缓存数据库所有的数据,2.重做日志能够无限增大。这几乎是不可能的(原因就不说了...),而且就算满足条件,宕机数据库恢复的时间会非常久。(说到底,就是得用Checkpoint技术,实现分批定时将数据刷新到磁盘)
Checkpoint(检查点)技术目的是解决如下问题:
缩短数据库的恢复时间;当发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新到磁盘。
缓冲池不够用时,将脏页刷新到磁盘;当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是新版本刷回磁盘。
重做日志不可用时,刷新脏页。所谓的不可用,是指重做日志的设计是循环使用的,并不是让其无限增大的,重做日志可以被重用的部分是指这些重做日志已经不再需要(应该是已经被刷回到磁盘),发生宕机时,恢复操作不需要这部分重做日志,因此这部分可以被覆盖重用,也即是上面说的重做日志不可用,但是如果想要使用不可用的重做日志,就需要强制使用Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置(这里和下面的分析有一些冲突)。
对于InnoDB存储引擎,通过LSN来标记版本的。而LSN是8个字节的数字,每个月有LSN,重做日志有LSN,Checkpoint也有LSN。
通过命令查看LSN。
show engine innodb status\G; LOG --- Log sequence number 33646077360 Log flushed up to 33646077360 Last checkpoint at 33646077360 0 pending log writes, 0 pending chkp writes 49687445 log i/o's done, 1.25 log i/o's/second在InnoDB存储引擎有两种Checkpoint,分别是:
Sharp Checkpoint
Fuzzy Checkpoint
Sharp Checkpoint发生在数据库关闭时将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数innodb_fast_shutdown = 1。
在内部使用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列表中需要有差不多100个空闲页可使用。如果没有100个空闲页,那么InnoDB会将LRU列表尾端的页移除。如果这些页中有脏页,那么需要进行Checkpoint,而这些页来自LRU列表。从MySql 5.6版本开始,这个检查工作被放在一个单独的Page Cleaner线程中进行,并且用户可以通过参数innodb_lru_scan_depth控制LRU列表中可用页的数量,默认为1024。