MySQL——checkpoint
CheckPoint技术
目标问题
如果每当一个页发生变化就将其写回磁盘那么开销会变得很大,而且如果热点数据都在这几个页中,需要频繁修改,频繁写回在读取磁盘,这样数据库性能会变得极差。除此之外,如果数据库在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么数据便无法恢复造成数据的丢失。
为了避免数据丢失的问题,事务数据库通常都会采用Write Ahead Log的策略,当事务提交的时候,先写重做日志再对页进行修改。当发生宕机而导致数据丢失的时候,可以通过重做日志来进行恢复。
场景:
如果,重做日志可以无限扩大,缓冲池也无限大,能够容纳所有数据库的数据,那么就不需要将缓存池中页的新版本写回到磁盘上,这样宕机的时候可以通过重做日志将数据库恢复到数据库系统宕机的时刻。很显然这两个必要条件,缓冲池可以缓存数据库中的所有数据以及重做日志可以无限增大,这是难以实现的,前者对内存的要求极高,后者如果运行几年的数据库宕机那么重做日志也会变成几年的量恢复时间会变得非常久。
所以检查点存在是为了解决以下问题:
- 缩短数据库的恢复时间
- 缓冲池不够用时将缓冲池内的数据刷新到磁盘上
- 重做日志不可用时,刷新脏页
这样可以实现在数据库宕机时不需要使用全部的重做日志 因为Checkpoint之前的页都已经刷新回磁盘所以只需要对数据库checkpoint以后的重做日志文件进行恢复即可,这样可以大大减少恢复时间。此外如果缓冲池不够用,根据LRU算法会释放最近最少使用的页,如果这个被释放的页是脏页那么需要强制执行Checkpoint,也就是将脏页刷回到磁盘上。
重做日志不可用这种情况主要出现在,因为事务数据库对redo的设计都是循环使用的,并不是让其无限增大。重做日志被重用部分是指这些重做日志已经不需要了,当数据库发生宕机的时候,数据库恢复操作不需要这部分重做日志,因此这部分重做日志可以被覆盖。
若此时重做日志仍需要被使用,必须强制产生checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
LSN
对于InnoDB引擎而言,通过LSN(Log Sequence Number)来标记版本的,LSN是8字节的数字单位字节。每个页都有LSN,重做日志也有LSN,Checkpoint也有LSN。一样可以使用show engine innodb status来观察。
mysql> show engine innodb status \G
...
---
LOG
---
Log sequence number 22762924
Log buffer assigned up to 22762924
Log buffer completed up to 22762924
Log written up to 22762924
Log flushed up to 22762924
Added dirty pages up to 22762924
Pages flushed up to 22762924
Last checkpoint at 22762924
30 log i/o's done, 0.00 log i/o's/second
...
在InnoDB存储引擎中,Checkpoint发生的时间,条件和脏页的选择都较为复杂。但是Checkpoint的作用都是将脏页刷新会磁盘,不同的地方在于每次刷新多少页到磁盘上,每次从哪里取脏页,以及什么时间触发Checkpoint。
Checkpoint的种类
[] Sharp Checkpoint
[] Fuzzy Checkpoint
Sharp Checkpoint发生在数据库关闭时将所有脏页都刷新回磁盘这是默认的工作方式,即参数innodb_fast_shutdown = 1,注意这个检查点发生在数据库关闭时,如果数据库正在运行时也是用sharp Checkpoint,那么会对数据库的性能造成较大的影响,所以在InnoDB存储引擎内部会使用Fuzzy Checkpoint进行页的刷新只会刷新一部分的脏页,而不是刷新所有的脏页回到磁盘。
Fuzzy Checkpoint
发生Fuzzy Checkpoint的几种情况:
Master Thread Checkpoint,FLUSH_LRU_LIST Checkpoint,Async/sync Flush Checkpoint,Dirty Page too much Checkpoint。
1)Master Thread Checkpoint中发生的Checkpoint,差不多以每秒或者每十秒的速度从缓冲池的脏页列表中刷新一定比例的页到磁盘上。这个过程是异步的,也就是说这个时候InnoDB存储引擎可以进行其他操作,用户的查询并不会阻塞。
2)FLUSH_LRU_LIST Checkpoint 是因为InnoDB存储引擎需要保证LRU链表中需要有差不多100个空闲页可供使用。如果不足,InnoDB存储引擎就会将LRU链表冷端的页移除,如果这些页中存在脏页,那么需要进行Checkpoint操作,因为这些页来自LRU所以称为FLUSH_LRU_LIST Checkpoin。
注意:关于查询LRU中剩余页是否充足这个操作,在InnoDB1.1.x之前是发生在用户的查询线程中的,所以这个操作是会导致用户的查询操作被阻塞。在InnoDB1.2.x(MySQL5.6以后)这个检查操作被放在了一个单独的线程中进行,并且用户可以通过参数 innodb_lru_scan_depth来控制LRU中可用页的数量,默认为1024;
mysql> show variables like 'innodb_lru_scan_depth';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 4000 |
+-----------------------+-------+
1 row in set (0.00 sec)
3)Async/sync Flush Checkpoint指的是重做日志文件不可用的情况,这需要强制将一些页刷新到磁盘上,而此时的脏页是从脏页列表中选取的,若将已经写入到重做日志的LSN记作redo_lsn,将已经刷新到磁盘上的最新页LSN记为checkpoint_lsn则可以定义为:
checkpoint_age=redo_lsn - checkpoint_lsn
关系为下:(为了保证redo日志的循环使用)
4)Dirty Page too much Checkpoint 即脏页的数量太多,导致InnoDB存储引擎强制进行Checkpoint。目的还是主要为了保证缓冲池中有足够可用的页。这个值可以通过参数innodb_max_dirty_pages_pct进行设置。
mysql> show variables like 'innodb_max_dirty_pages_pct';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 11
Current database: *** NONE ***
+----------------------------+-----------+
| Variable_name | Value |
+----------------------------+-----------+
| innodb_max_dirty_pages_pct | 50.000000 |
+----------------------------+-----------+
1 row in set (0.00 sec)
这个值50表示,当缓冲池中的脏页数量占据50%的时候,InnoDB存储引擎会强制进行检查点,刷新一部分脏页到磁盘上。