Mysql - 脏页

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql - 脏页相关的知识,希望对你有一定的参考价值。

参考技术A 当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。

不论是脏页还是干净页,都在内存中。

平时很快的更新操作,都是在写内存和日志。

一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢。

那这时候可能就是在刷脏页到磁盘中了~ flush

(1) InnoDB的redo log写满了。这时候系统会停止所有的更新操作,然后让日志可以继续写。

把这部分数据日志都flush到磁盘上面。

(2) 也可能是系统内存不足,需要新的内存页,那么就淘汰一些内存页,空出来的给别的数据页使用。

先把脏页写到磁盘。

PS:使用内存是为了效率更好,

因为如果内存存在数据页,那么数据就一定正确,直接返回;

如果内存没有数据,才需要去磁盘中取,读入到内存,返回;

(3) mysql 认为系统“空闲”的时候,反正闲着也是闲着hh

反正有机会就刷点数据

(4)MySQL 正常关闭。这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。

3.1 如果是redo log写满了
尽量避免的。因为出现这种情况的时候,整个系统就不能再接受更新了,所有的更新都必须堵住。更新数为 0。

3.2 内存不够用了
常态,很正常。

3.3 buffer pool
因为innodb用的是buffer pool 管理内存,缓冲池中的内存页有三种状态:第一种是还没有使用的;第二种是使用了并且是干净页;第三种是使用了并且是脏页。

Innodb 的内存策略是尽量使用内存。

我觉得知道一下就好,这个脏页刷的快不快跟磁盘的能力有关。

可以通过innodb_io_capacity 这个参数设置磁盘能力。

InnoDB 的刷盘速度就是要参考这两个因素:一个是脏页比例,一个是 redo log 写盘速度。

平时要多关注脏页比例,不要让它经常接近 75%。

INNODB刷脏页,如果发现旁边也是脏页,那么会连带着一起刷掉。

所以可能会很慢,如果你的查询正好要先flush一个脏页的话。

在 InnoDB 中,innodb_flush_neighbors 参数就是用来控制这个行为的,值为 1 的时候会有上述的“连坐”机制,值为 0 时表示不找邻居,自己刷自己的。

找“邻居”这个优化在机械硬盘时代是很有意义的,可以减少很多随机 IO。机械硬盘的随机 IOPS 一般只有几百。

但是SSD 的IO很高,所以可以不用非要有刷写邻居的操作,可以加快响应。

在 MySQL 8.0 中,innodb_flush_neighbors 参数的默认值已经是 0 了。

对比这个LSN跟checkpoint 的LSN,比checkpoint小的一定是干净页

也就是如果内存中比redolog的头部小,那么就是干净页

每个数据页有LSN,重做日志有LSN,checkpoint有LSN。

占用8字节,LSN主要用于发生crash时对数据进行recovery,LSN是一个一直递增的整型数字,表示事务写入到日志的字节总量。
LSN不仅只存在于重做日志中,在每个数据页头部也会有对应的LSN号,该LSN记录当前页最后一次修改的LSN号,用于在recovery时对比重做日志LSN号决定是否对该页进行恢复数据。前面说的checkpoint也是有LSN号记录的,LSN号串联起一个事务开始到恢复的过程。

感谢: https://www.cnblogs.com/drizzle-xu/p/9713378.html

我感觉就是可以理解为是一个long类型的数字,可以根据这个来比较要不要刷写数据,以及是不是干净页面,在恢复数据要拿这个进行比较。

缓存区域,缓存数据和索引在内存中。

innodb使用了一些链表。
lru链表:用来存储内存中的缓存数据。
free链表:用来存放所有的空闲页,每次需要数据页存储数据时,就首先检测free中有没有空闲的页来分配。
flush链表:在内存中被修改但还没有刷新到磁盘的数据页列表,就是所谓的脏页列表,内存中的数据跟对应的磁盘上的数据不一致,属于该列表的页面同样存在于lru列表中,但反之未必。

将脏页flush到磁盘上是直接将脏页数据覆盖到对应磁盘上的数据

Mysql刷脏页的二三事

我们知道MySQL 的innodb引擎使用redo log 实现crash safe, 并且更新数据时,先更新内存,然后写完redo log,然后后台线程将redo log 异步刷入磁盘。

内存与磁盘的数据页不一致,这样的数据页叫做脏页,mysql偶尔查询慢,可能就是在刷脏页到磁盘,刷脏页有几种情况:

  1. redo log 写满了
  2. mysql内存满了,发生内存置换。当要置换出去的是脏页时,就会刷脏页
  3. mysql系统空闲时
  4. mysql停止服务的时候

1和2才是我们关注的对象,redo log写满了,必须停下来刷脏页,此时完全完全不能写入。innodb 使用buffer pool管理内存,如果要查询的数据不在内存中,需要从磁盘读入内存,可能会淘汰掉一批很久没使用的数据页。如果淘汰的数据页比较多,会花时间去刷脏页,造成的影响就是查询变慢了。

刷脏页的控制策略

innodb_io_capacity

这个参数设置为磁盘的IOPS,机械磁盘一般为300,SSD的话往上配置。

innodb_max_dirty_pages_pct

参数 innodb_max_dirty_pages_pct 是脏页比例上限,默认值是 75%。当前的刷脏页比例,由附件"InnoDB 刷脏页速度策略"。假设当前脏页比例为M,有如下计算规则:

F1(M)

     if M >= innodb_max_dirty then 
         return 100;
     return 100*M/innodb_max_dirty_pages_pct;

另外还有个计算规则,记为F(N), N代表了redo log当前的余裕部分大小(当前写入日志位置序号和checkpoint位置序号的差值)。

刷脏页速度大概可以这样给出公式

innodb_io_capacity * max(F(M), F(N)) x !00%

合理设置 innodb_io_capacity 的值,并且平时要多关注脏页比例,不要让它经常接近 75。

监控刷脏页

use information_schema;
set @@global.show_compatibility_56=ON;
select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = \'Innodb_buffer_pool_pages_dirty\';
select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = \'Innodb_buffer_pool_pages_total\';
select @a/@b;

innodb_flush_neighbors

innodb_flush_neighbors 设置为1 时,表示刷脏页的时候会连带将附近的脏页一起刷盘,设置这个参数对机械键盘有用,如果时SSD iops比较高,可以关掉,减少一些sql语句响应时间。

以上是关于Mysql - 脏页的主要内容,如果未能解决你的问题,请参考以下文章

mysql查询重复数据sql,移动架构师成长路线

mysql图形化界面创建数据库,看完直接跪服

大厂Java面试总结+详细解答!极其重要

万字总结!springcloud分布式限流

Java开发必会技术!安卓安装docker

Java开发工程师面试题!javaweb视频教程推荐