引子
缓冲池的设计目的为了协调 CPU 速度和磁盘速度的鸿沟。因此页的操作首先都是在缓冲池中完成的。
如果一条DML语句,如 Update 或 Delete 改变了页中的记录,那么此时页是脏的,即缓冲池中的页的版本要比磁盘的新。数据库需要将新版本的页(脏页)从缓冲池刷新到磁盘。
对于 InnoDB 存储引擎而言,其是通过 LSN(log Sequnence Number,8字节的数字,其单位是字节)来标记版本的。
每个页、重做日志、Checkpoint 都有 LSN。
若一个页发生变化就把新页的版本刷新到磁盘,这个开销是非常大的。
若热点数据集中在某几个页中,数据库的性能也会变得非常差。
如果在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么数据就不能恢复了。
为了避免数据丢失的问题,当前事务数据库系统普遍采用了 WAL (Write Ahead Log)策略,即当事务提交时,先写重做日志(redo log),再修改页。即先写日志,再写磁盘。
当由于发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复,这也是事务 ACID 中 D(Durabilty 持久性)的要求。
一、为什么需要 Checkpoint ?
既然重做日志可以避免因宕机而造成的数据丢失的问题,那么如果
- 重做日志可以做到无限地增大
- 并且缓冲池也足够大到能够缓冲所有数据库的数据
我们就不需要将缓冲池中的页的新版本刷新回磁盘。
可是,第一点假设可以做到,但成本高,不便于运维,实现难度大。
第二点,内存造价高且 3TB 的 MySQL 数据库不少见,但 3TB 的内存却非常少见。
除此之外,如果发生宕机且数据库运行了较长一段时间,重新应用重做日志的时间会非常久,数据库恢复时间太久,恢复代价太大。
因此 Checkpoint(检查点)技术的目的是解决以下几个问题:
- 缩短数据库的恢复时间;
- 缓冲池不够用时,将脏页刷新到磁盘;
- 重做日志不可用时,刷新脏页。
二、Checkpoint 简介
![](https://img-blog.csdnimg.cn/f53cb29133104b18891f2c1d0754ee06.png)
在上图中,write pos 表示 redo log 当前记录的 LSN(逻辑序列号)位置,一边写一边后移。
check point 表示数据页更改记录刷盘后对应 redo log 所处的 LSN(逻辑序列号)位置。也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
write pos 到 check point 之间的部分是 redo log 空着的部分,用于记录新的记录;
check point 到 write pos 之间是 redo log 待落盘的数据页更改记录。
当 write pos 追上 check point 时,会先推动 check point 向前移动,空出位置再记录新的日志。
使用 Checkpoint 技术,当数据库发生宕机时,数据库不需要重做所有的日志,因为 Checkpoint 之前的页都已经刷回磁盘。
InnoDB 存储引擎内部有以下两种 Checkpoint。
-
Sharp Checkpoint
发生在数据库关闭时,将内存中的所有脏页都刷新到磁盘中。
此时 redo log 就没用了,因为内存和磁盘中的数据一致,并且会刷新 Checkpoint,Checkpoint 就为空了。 -
Fuzzy Checkpoint
发生在数据库运行时,只刷新一部分脏页到磁盘中。
![](https://img-blog.csdnimg.cn/62ceced00c024f1e9b945f2c1bc4bc78.png)
空闲页太少。InnoDB 存储引擎需要保证 LRU 列表中需要有差不多100个空闲页可供使用。
需要检查 LRU 列表中是否有足够的可用空间操作 发生在用户的查询线程中(该检查操作已被放在一个单独的 Page Cleaner 线程中,故不会阻塞用户的查询操作)。
如果没有100个可用空闲页,InnoDB 存储引擎会将 LRU 列表尾端的页移除。如果这些页中有脏页,那么需要进行 Checkpoint。
注意,这些都是 LRU 列表中的脏页。
参考资料
[1] MySQL技术内幕 InnoDB存储引擎 第2版