show engine innodb status中Pages
有一个很久前就存在的疑惑:
在没有写入的情况下,show engine innodb status 中的 Pages flushed up to 为什么不等于 Last checkpoint point?它表示什么?
今天在写一篇文章时,想通过一个测试,从这几个 LSN 的变化来验证一个说法,结果重新勾起了这个问题,在一番“研究”后(其实就是google了一通,当然还是需要一些测试验证),终于弄明白了其中含义。
主要还是借鉴了一篇文章:http://blog.itpub.net/30221425/viewspace-2154670/,因为有大量的源码分析,而我看不懂源码,所以花了不少时间才理解其中原理,并且通过测试验证了其准确性,然后整理成了一个让像我这样不懂代码的人更方便阅读的文档。
LSN
show engine innodb status
的输出中,有一部分是 LSN 的状态:
mysql> pager grep -A 5 LOG
PAGER set to 'grep -A 5 LOG'
mysql> show engine innodb status\G
LOG
---
Log sequence number 2471197058
Log flushed up to 2471197058
Pages flushed up to 2471197058
Last checkpoint at 2471197049
1 row in set (0.00 sec)
Log sequence number:所有修改数据的操作都会产生 redo log,这是系统当前 redo log 序列号(后面简称 LSN)的最大值;
Log flushed up to:当前已经刷盘的 redo log 的序列号;
Pages flushed up to:讨论的重点;
Last checkpoint at:最后一次 checkpoint 的位置。
Pages flushed up to 到底表示什么?最常见的说法就是脏页刷新到磁盘的 LSN,但 Last checkpoint at 也表示在此之前的数据页已经刷盘,而且通常我们看到的 Pages flushed up to 总是比 Last checkpoint at 大 ,所以这个说法肯定是错误的。
根据参考文章中的源码分析,Pages flushed up to 的取值逻辑是:
Pages flushed up to 取的是 buffer pool instance 中的所有 flush list 尾部的数据页中最小的 oldest modification lsn 的值;
如果取到的 oldest modification lsn 为 0,意味着没有脏页,那么就取 log_sys->lsn 的值,即 show engineinnodb status 显示的 Log sequence number。
在没数据写入的情况下,为什么 Last checkpoint point 不等于 Pages flushed up to?
是因为做 checkpoint 时同时 redo 日志会写 MLOG_CHECKPOINT,而 MLOG_CHECKPOINT 占用9个字节,所以系统 LSN 会加9,而由于脏页都被刷盘了,flush list 为空,获取 Pages flushed up to 时会直接取系统 LSN 值,所以也会比 Last checkpoint point 大 9。
获取 Pages flushed up to 和 checkpoint 不是一个原子操作,它是在 checkpoint 前就获取了,指的是下一次 checkpoint 结束的位置。
测试验证
我们手工开启一个事务写入一行数据(不提交),会发现如下图所示:
- Log sequence number 增加了,因为系统 LSN 是实时产生的;
- Log flushed up to 没变,说明 redo log 还没刷盘(也可能观察到这个值增加并且和 Log sequence number 一致,因为 InnoDB 后台线程每秒会刷 redo log,未提交事务的 redo log 可能提前刷盘);
- Pages flushed up to 没变,因为这个值不是实时产生的,只要我们手速够快,在执行完 insert 后立刻查看 LSN,就可以看到这个值不变;
- Last checkpoint point 没变,同样的只要手速够快,在 checkpoint 前查看到的值就不会变。