mysql checkpoint

checkpoint机制,主要干的事情就是把脏页刷新到磁盘。

数据库只能保证最终一致性。你在数据库运行的时候,磁盘上的数据和内存中的数据不一致太正常了。

另外checkpoint也能保证数据库在挂了,或者出事了之后,缩短他的恢复时间。这个很好理解,MySQL有redo和binlog去保证事务的持久性。所以即使你数据没有落盘,也没关系,他是有日志的。但是,如果没有checkpoint,你日志跑了1周,这时候你MySQL挂了,你重做日志需要多久。这个是很慢的。所以checkpoint能保证数据能有效地落盘,缩短recover时间。

 

而内存中这么多页,MySQL怎么知道哪些是脏页需要落盘,哪些不是脏页。这就引出了我们之前说的flush list。

 

首先,每个页有一个LSN,而MySQL整个实例,有一个全局的LSN,你可以把这个LSN理解成checkpoint,最后redo log里还有一个LSN。整个MySQL体系下,就这三个地方有LSN。

这么聊很难理解,我举一个例子。

page 1 被加载到bp里,初始的lsn是100,然后这个页被修改了,事务提交了。假设此时MySQL全局lsn是200,那么page 1的lsn被修改为200,并且写入redo log。

过了一段时间 page 2被加载到bp里,初始的lsn是110,然后这个页也被修改了,事务提交了。假设此时MySQL全局lsn是500,那么page 2的lsn被修改为500,并写入redo log。

然后,下一个时间,触发checkpoint。page 1作为最后一页被写入进磁盘了。page 2没有被写入。紧接着,mysql挂了。那么MySQL再次启动时,就会重放200-500之间的lsn。

而这个lsn究竟代表的是什么?

其实代表的是此次操作所产生的log字节数。 

 

然后lsn你可以show engine innodb status\G查看,在log部分下

last checkpoint at就是当前最后一次进行checkpoint位置的lsn。

page flushed up to 就是当前最大或者说是最新的刷新到磁盘上的lsn。

log sequence number 表示当前内存中redo log buffer的lsn。

log flushed up to表示刷新到redo log上的lsn。

 

原则上last checkpoint at <= page flushed up to

比如说,我有一个页,lsn80,被加载到内存。此时全局lsn是100。这时候,这个页被修改了,产生了20字节的log。那么这个页lsn变成120,并且被放到flush list中。

然后这个页又被修改了,又多了20字节的log。此时lru list中这个页lsn是140。但是flush list中,这个页的lsn是不会变的。因为flush list的组织方式,是用的这个页第一次被加载进来的lsn来组织的。

所以这时候,第一个lsn是120,下面的三个lsn是140.

之前有提到innodb_buffer_page_lru这个表。其中有两个字段,NEWEST_MODIFICATION 和  OLDEST_MODIFICATION。这两个字段也是内存中真实存在的。这也就是之前为什么我说大家在线上环境要慎用这个表。这是要扫内存的。开销很大。

后者表示页第一次被更新时的lsn,对应这个例子是120,前者是内存中最新的lsn,对应这个例子是140。

 整个flush list就是由OLDEST_MODIFICATION从小到大排序。刷脏页的时候,也是由OLDEST_MODIFICATION最小的开始。而checkpoint就是脏页列表中那个最小的OLDEST_MODIFICATION。

写入磁盘后,这一页的lsn也就变成140了。

也就是说last checkpoint at是120.

page flushed up to是140.

这时候数据库crash了。MySQL从120的lsn开始重做,然后发现这个页已经刷新到140了,跳过。更新下一个lsn,当前,这个例子是没有下一个lsn了。你可以想象在120和140之间有其他操作,但是没有落盘。

这部分很难,还是要多理解。

对了chencopint的值是要落盘的,在ib_logfile的第一个文件的前面两个字节。但这个值不是你刷了脏页就一定会落盘。因为lsn小一点没事的。你最多就是scan的时候多扫描一点。反正都落盘了,page的lsn大于mysql的lsn,他就直接跳过了。写checkpoint实际上是在master thread中,每一秒会更新一次。

 

接下来说一下checkpoint的类别。

官方文档明确的分为了两种。

fuzzy checkpoint 和sharp checkpoint。

前者刷新部分脏页,对系统影响小。

后者是刷新全部脏页,比如在shutdown时。

 

而fuzzy checkpoint的时机有以下:

page cleaner threads,每1s和10s固定时间刷新。

脏页比例过大(由参数innodb_max_dirty_pages_pct控制,默认75)

以上两种情况都是page cleaner threads主动从flush list中刷新脏页。

以下的情况则是从lru list中进行判断:

flush_lru_list checkpoint

比如,你现在free list中已经没有页了 ,但是现在你需要加载一个页。那么你就需要到lru list中,在old段,找到最后一个页,淘汰。

然而很不幸,这个页是脏页。这个时候就会进行刷新。

这时,就会由innodb_lru_scan_depth这个参数进行控制。就是发生如上情况,你需要淘汰最后一个页,但是最后一个页是脏页,那么MySQL会探测排在最后的innodb_lru_scan_depth个数的页。并将其中的脏页刷新。

 

async/sync flush checkpoint

未完待续

posted @ 2022-06-28 00:47  拿什么救赎  阅读(379)  评论(0编辑  收藏  举报