平静的快乐1989 发表于 2023-5-4 18:42:20

MySQL中 LSN 和 Checkpoint 关系

为什么需要Checkpoint技术?

考虑如下场景:假如redo-log重做日志可以无限增加,而且buffer-pool数据池足够大,那么就不需要将MySQL写入的缓冲池的数据页面刷回到磁盘。因为当主机crash时候,恢复数据库变得很容易,从无限容量的redo重做日志中对磁盘中的数据页面进行重放就可以了。
但这有必需有至少二个前提条件:

[*]数据库的buffer-pool可以缓存所有的页面数据
[*]Redo-log重做日志可以无限增长
显然上面二个前提约束条件是不成能成立的。
为了解决如下问题,checkpoint查抄点技术应运而生:

[*]缩短数据库从crash中恢复的时间
[*]MySQL buffer-pool缓冲池有上限,脏页面需要按时刷新回磁盘
[*]重做日志redo-log不能无限增长
有了checkpoint技术,当数据库从crash恢复时,数据库不需要重放执行所有的重做日志,因为checkpoint查抄点(小于checkpoint_lsn的值)前面的脏页面已经安全刷回磁盘了。数据库只需要执行查抄点之后的脏页面来进行恢复,从而大大减少了恢复的时间。

在讨论实现机制前,还需要先讨论一些关键概念。
MySQL在持久化与性能之间做了很多权衡与折衷。数据记录的改削首先写入buffer-pool内存中,但是为了将随机IO转换成挨次IO,会将数据记录对数据库改削所对应的物理日志写入redo-log缓存中。更进一步,或直接或间接的后台线程将数据写入OS buffer后,最后再同步磁盘中。
Buffer pool -> log Buffer -> os Buffer -> Log files on disk




LSN概述

LSN (log sequence number)是日志的逻辑序列号,在InnoDB存储引擎中,LSN的值会随着日志的写入而逐渐增大。新的日志LSN等于旧的LSN加上新增日志的大小。
LSN的分类?

每个页面都有 LSN,重做日志redo-log也有 LSN,查抄点checkpoint也有 LSN。可以使用如下命令来不雅察看:
mysql> show engine innodb status\G;


此中:

[*]log sequence number: 代表当前的重做日志redo log(in buffer)在内存中的LSN
[*]log flushed up to: 代表刷到redo log file on disk中的LSN
[*]pages flushed up to: 代表已经刷到磁盘数据页上的LSN
[*]last checkpoint at: 代表上一次查抄点地址位置的LSN
LSN的存储位置?




LSN不仅存在于重做日志redo log,还存在于普通数据页面中,每个数据页面的头部有FIL-PAGE_LSN字段,它记录了当前数据页最后一次被改削时日志序列LSN值。

按照上图流程,更新一笔记录时:

[*]先写内存数据页面(内存的数据页面有LSN字段)
[*]然后写缓冲内存的重做日志redo-log(内存的重做日志redo-log记录有LSN字段)
[*]最后提交时innodb_flush_log_at_trx_commit写重做日志redo-log进磁盘文件(磁盘的redo-log日志记录有pageLSN字段)
简言之,LSN这个值在几个处所存储:

[*]在数据页面(内存与磁盘)存储LSN
[*]在重做日志redo-log(内存)存储LSN
[*]在重做日志redo-log(磁盘)存储LSN
[*]Checkpoint对应的LSN也是存储在重做日志记录中
恰好对应上文:
mysql> show engine innodb status\G;

[*]log sequence number: 代表当前的重做日志redo log(in buffer)在内存中的LSN
[*]log flushed up to: 代表刷到redo log file on disk中的LSN
[*]pages flushed up to: 代表已经刷到磁盘数据页上的LSN
[*]last checkpoint at: 代表上一次查抄点地址位置的LSN
问题1:MySQL怎么判断脏页?

基于数据页面的LSN,可以了解当前数据页面的版本。MySQL系统在更新记录时,会在对应的重做日志redo-log中更新LSN的值,与此同时记录的数据页面的头部也会记录redo-log中的LSN最新的值。当MySQL刷脏数据页面时,磁盘中数据页面文件的LSN的值也会增加。
回到我们的问题,MySQL怎么判断脏页?
只需要判断这个页面的LSN值,如果数据页面的LSN的值大于 Checkpoint的LSN值,说明这个数据页面接受了新的更新(所有数据页面的LSN更新到更大的值)。那么这个页面就是脏页。
问题2:MySQL基于Checkpoint如何从crash中恢复?

MySQL在崩溃恢复时,会从重做日志redo-log的Checkpoint处开始执行重放操作。 它从last Checkpoint对应的LSN开始扫描redo-log日志,并将其应用到buffer-pool中,直到last Checkpoint对应的LSN等于 log flushed up to 对应的 LSN (也就是redo-log磁盘上存储的LSN值),则恢复完成 。
说白了,查抄点要做的操作就是将缓冲池中的数据页刷到磁盘,最终达到内存与外存数据页的一致。查抄点的感化是縮短当数据库发生crash时数据库恢复所需要的时间。
尽管从理论上来说,由于重做日志redo-log记录了所有的页操作,当数据库crash时,恢复重做日志redo-log即可。但考虑到数据库是一个需要保证高可用的应用环境,从crash环境中快速恢复回来对处事的可用性是一个关键指标。因此查抄点checkpoint机制就是将内存页写加磁盘,这样发生crash的时候,已经刷到磁盘的数据页就不再需要恢复,只需要恢复查抄点之后的操作。

yingyouhei111 发表于 2023-5-4 18:42:42

请教一下 pages flushed up to和last checkpoint at之间为什么会有gap呢

葭娤 发表于 2023-5-4 18:43:42

pages flushed up to指的是脏页中的最大的LSN,是下一次刷新checkpoint的终点

hldprswd 发表于 2023-5-4 18:44:24

讲得很明白,一下子我就理解了整个过程。真牛。
页: [1]
查看完整版本: MySQL中 LSN 和 Checkpoint 关系