1、Redo Log 重做日志
前面已经提到,使用 缓冲池技术的原因是为了协调 CPU 以及磁盘速度。页数据的改变通常在缓冲池中执行。如果一条 DML 语句修改了数据造成缓冲池和磁盘中数据不一致的问题。那么此时的页称之为脏页(dirty page)。数据库需要将脏页刷新到磁盘中。但是倘若每一个页变成脏页就要执行一次刷新操作,那么其开销是非常大的。当刷新到磁盘的时候发生宕机,可能就会造成数据丢失,所以事务系统通常采用 Write Ahead Log 的方式,先写重做日志,然后在修改页,如果发生数据丢失通过重做日志完成数据恢复,这也是事务中 ACID 中的 D 的体现。
如果缓冲池空间大小足够大,并且重做日志空间大小也足够大,能够缓冲数据库所有的数据的时候,那么当服务宕机的时候,完全可以通过重做日志恢复数据。这种方式理论上是可以的,但是必须满足缓冲池以及重做日志空间足够大的前提条件。但是当数据库运行几个月甚至几年之后这时候发生宕机,通过重做日志恢复数据的时间将非常长,此时恢复数据的代价很大。
2、Checkpoint
因此Checkpoint技术就是解决这些问题,缩短数据库恢复的时间,将脏页刷新到数据库中以及重做日志不可用时,刷新脏页。
- 缩短数据库恢复时间
当数据库服务不可用的时候,数据库并不需要重做所有的日志,仅仅需要重做 Checkpoint 之后的日志记录,因为在 Checkpoint 之前的日志已经刷新到磁盘中。所以这种方式就可以大大缩短数据库恢复的时间。
- 缓冲池不够的时候,刷新脏页数据到磁盘中
当缓冲池空间不够的时候,根据LRU 算法,此时会溢出不常用的页数据,那么存储引擎会强制执行 Checkpoint ,将溢出的脏页数据刷新到磁盘中。
- 重做日志不可用时候,刷新脏页数据到磁盘中
重做日志出现不可用的时候,是因为当前数据库事务系统对重做日志设计都是循环使用的,并不是让其无限增大。所以重做日志可以被覆盖的部分是已经不需要的部分。但是倘若重做日志还是需要的额,此时就需要必要强制Checkpoint,刷新数据。
3、Checkpoint 的分类
Checkpoint 大致可以划分为 两类: Sharp Checkpoint & Fuzzy Checkpoint。 前者是在数据库关闭的时候将所有的脏页刷新到磁盘中,这是默认的工作方式,即参数 innodb_fast_shutdown = 1
。但是对于 Fuzzy Checkpoint 而言,其可能会发生于以下场景。
- Master Thread Checkpoint
MasterThread 每个1s或者10s就会执行一次 Checkpoint,刷新一定比例的脏页到磁盘中,此操作是异步的。
- Flush LRU List Checkpoint
InnoDB 存储引擎需要保证有100个空闲页可用,当没有100个空闲页可用时候,会将 LRU 列表尾部数据移除,此时就会需要 Checkpoint。
-
Async/Sync Flush Checkpoint
-
Dirty Page too much Checkpoint
当缓冲池中脏页太多的时候,超过一定的比例的时候会强制执行Checkpoint,这个比例在参数 innodb_max_dirty_pages_pct
定义,比如下面的数据显示,当脏页数据超过整个 LRU 列表的 90% 的时候回强制 Checkpoint。
mysql> show variables like 'innodb_max_dirty_pages_pct';
+----------------------------+-----------+
| Variable_name | Value |
+----------------------------+-----------+
| innodb_max_dirty_pages_pct | 90.000000 |
+----------------------------+-----------+
1 row in set (0.01 sec)