缓冲池的设计是为了协调CPU速度和磁盘速度不一致,对于页的操作首先都会在缓冲池中进行。当我们执行update操作时,改变了页中的记录,那此时的页就是脏页,即缓冲池中的页的数据比磁盘的新。数据库需要把新数据刷新到磁盘,以满足数据一致性。
如果是一个页发生变化,就把新数据刷回磁盘,这个开销是非常大的。而且如果在将数据刷新到磁盘的过程中发生了宕机,那么数据就不能恢复了。
为了避免数据丢失,事务数据库系统普遍采用Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页。当发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复。
如果重做日志可以无限增大,同时缓冲池也足够大,能够缓存数据库中的所有数据,那么我们就不需要再把缓冲池中页中的新版本刷新回磁盘。因为发生宕机时,我们可以通过重做日志来恢复。
但一般这种情况是不满足的,首先如果要使缓冲池能够缓存数据库的所有数据,那数据库的容量要求很大,当前3TB的MySQL数据库并不少见,但是3TB的内存却非常少见。重做日志无限增大也许是可以的,但是成本会非常高,同时也不便于运维。
checkpoint技术的目的就是解决以下问题:
- 缩短数据库恢复时间
- 缓冲池不够用时,将脏页刷新回磁盘
- 重做日志不可用时,将脏页刷新回磁盘
当数据库发生宕机时,不需要执行所有的重做日志,因为Checkpoint之前的页都已经刷新回磁盘。数据库只需要对Checkpoint后的重做日志进行恢复即可,这大大的缩短了恢复的时间。
当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页刷新回磁盘。
重做日志出现不可用的情况是因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让其无限增大的,这从成本以及管理上都是比较困难的。重做日志被重用的部分,是指这部分的重做日志已经不再需要,即发生宕机时,不再用来恢复数据,可以被覆盖重用。若此时重做日志还需要使用,那么必须强制产生checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
对于InnoDB存储引擎而言,其是通过LSN(Log Sequence Number)来标记版本的,LSN是8字节的数字,其单位是字节。每个页有LSN,重做日志有LSN,Checkpoint也有LSN。
通过show engine innodb status;命名查看
——LOG——
Log sequence number 164641265
Log flushed up to 164641265
Pages flushed up to 164641265
Last checkpoint at 164641256
0 pending log flushes, 0 pending chkp writes
10 log i/o’s done, 0.00 log i/o’s/second
简单来说,Checkpoint所做的事情就是将缓冲池中的脏页刷新回磁盘。
每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发Checkpoint,这些是有一定差别的。
在InnoDB存储引擎内部,有两种Checkpoint
- Sharp Checkpoint 刷新所有脏页
- Fuzzy Checkpoint 刷新一部分脏页
Sharp Checkpoint:默认的方式,数据库关闭时将所有的脏页都刷新回磁盘。
参数innodb_fast_shutdown = 1
Sharp Checkpoint这种方式显然会影响到数据库的可用性,所以在InnoDB存储引擎内部使用Fuzzy Checkpoint进行页的刷新,即只刷新一部分脏页。