学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • Java基础

  • Java集合

  • MySQL

    • MySQL深入01-查询语句
    • MySQL深入02-更新语句
    • MySQL深入03-事务隔离
    • MySQL深入04-深入浅出索引
    • MySQL深入05-全局锁、表锁、行锁
    • MySQL深入06-事务隔离再探
    • MySQL深入07-普通索引和唯一索引
    • MySQL深入08-为什么会选错索引
    • MySQL深入09-字符串字段加索引
    • MySQL深入10-脏页刷新
      • MySQL深入-脏页刷新
      • 脏页刷新的四种场景
        • 场景1-redo log写满
        • 场景2-内存不足
        • 场景3-空闲状态
        • 场景4-关闭
      • 四种场景的性能影响
      • InnoDB刷脏页的控制策略
      • 参考
    • MySQL深入11-数据库表空间回收
    • MySQL深入12-count()
    • MySQL深入13-order by
    • MySQL深入14-正确显示随机消息
    • MySQL深入15-索引失效案例分析
    • MySQL深入16-查询一行数据执行慢
    • MySQL深入17-幻读
    • MySQL深入18-改一行语句锁问题
    • MySQL深入19-暂时提高数据库性能方案
    • MySQL深入20-这么保证数据不丢
    • MySQL深入21-主备一致的保证
    • MySQL深入22-高可用性的保证
    • MySQL深入23-备库延迟好几个小时
    • MySQL深入24-主库出问题,从库这么办
    • MySQL深入25-读写分离的过期读问题
    • MySQL深入26-判断数据库是否出问题
    • MySQL深入27-误删数据的处理方案
    • MySQL深入28-kill不掉的语句
    • MySQL深入29-查询对内存的影响
    • MySQL深入30-join深入
    • MySQL深入31-join语句优化
    • MySQL深入32-临时表深入
    • MySQL深入33-内部临时表何时使用
    • MySQL深入34-InnoDB和Memory
    • MySQL深入35-自增主键为什么不连续
    • MySQL深入36-insert语句的锁
    • MySQL深入37-如何快速复制一张表
    • MySQL深入38-grant和flush privileges
    • MySQL深入39-分区表
    • MySQL深入40-自增id用完如何处理
  • Redis

  • JVM

  • 多线程

  • 计算机网络

  • Spring

  • Kafka

  • Elasticsearch

  • Python

  • 面试专题

  • 知识库
  • MySQL
旭日
2023-03-31
目录

MySQL深入10-脏页刷新

# MySQL深入-脏页刷新

在redo log中有一个关键机制:WAL,它类似于草稿本的形式,减少了写磁盘的次数,大大提高了数据库磁盘I/O操作的效率,从而提高了数据库的性能。

但是草稿本的内容终究是要写入试题卷,相当于内存里的数据终究要写入磁盘。这个过程就是flush。在flush之前,内存里的数据和磁盘里的数据是不一致的。

脏页: 当内存数据页跟磁盘数据页内容不一致的时候,这个内存页被称为脏页。

干净页: 内容数据写入磁盘后,内存和磁盘上的数据页内容一致后,这个内存页就被称为干净页。

平时执行很快的更新操作,其实就是在写内存和日志,而MySQL偶尔抖一下的瞬间,可能就是在刷脏页(flush)。

# 脏页刷新的四种场景

# 场景1-redo log写满

场景1就好比在只有一张草稿纸的情况下,如果草稿纸已经写满了,你就只能把草稿纸一部分内容记录到试题卷上,记录完毕之后再擦掉这部分内容。

这个场景,对应的就是 InnoDB 的 redo log 写满了。这时候系统会停止所有更新操作,把 checkpoint 往前推进,redo log 留出空间可以继续写。

image-20220612102431951

在上图中,checkpoint 位置从 CP 推进到 CP’,就需要将两个点之间的日志(浅绿色部分)所对应的所有脏页都flush到磁盘上。之后,图中write pos到CP’之间就是可以再写入到redo log的区域。

# 场景2-内存不足

假设A的记忆最多能记10件事情,现在已经记下了7件事情,现在又来了5件事情需要记录,由于记忆不到那么多,就需要把之前记下的事情先写入日记本。这个记忆就相当于内存,记忆不下那么多,相当于内存不够。

当需要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用。如果淘汰的是“脏页”,就要先将脏页写到磁盘。

# 场景3-空闲状态

MySQL认为系统空闲的时候,或者即使MySQL比较忙,但是也会忙中偷闲,只要找到机会就刷一点脏页。

# 场景4-关闭

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

# 四种场景的性能影响

由于场景3是空闲状态,场景4是临近关闭状态,这两种场景是不太需要关注性能问题的,所以我们重点分析场景1和场景2。

场景1

redo log写满了,要flush脏页。这种情况是需要避免的。因为在这种情况下,系统是暂时不接受更新的,所有的更新相当于阻塞了。

场景2

内容不够用了,先将脏页写到磁盘。这种情况是常态。

InnoDB用缓冲池(buffer pool)管理内存,缓冲池的内存页有三种状态:

  • 没有使用的
  • 使用了并且是干净页
  • 使用了并且是脏页

InnoDB的策略是尽量使用内存,因此对于一个长时间运行的库来说,未被使用的页面很少。

如果要读入的数据页没有在内存中,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉:

  • 如果淘汰的是一个干净页,就直接释放出来复用。
  • 如果是脏页,就必须将脏页刷到磁盘,变成干净页才能复用。

在刷新脏页的时候,如下的情况会明显影响性能:

  1. 一个查询要淘汰的脏页个数,就会导致查询的时间响应变长。
  2. 日志写满,更新全部堵住,写性能跌为0。

因此需要一个控制脏页比例的机制,来避免上面出现的情况。

# InnoDB刷脏页的控制策略

首先,要正确地告诉 InnoDB 所在主机的 IO 能力,这样 InnoDB 才能知道需要全力刷脏页的时候,可以刷多快。这就要用到 innodb_io_capacity 这个参数了,它会告诉 InnoDB 你的磁盘能力。这个值建议设置成磁盘的 IOPS。

现在已经定义了全力刷脏页的行为,现在我们就需要InnoDB按照全力的百分比刷脏页,这样把一部分磁盘能力去服务用户请求之类的。

我们需要避免的就是:1、内存脏页太多。2、redo log写满。所以InnoDB需要控制的就是脏页的比例和redo log写磁盘的速度。

参数 innodb_max_dirty_pages_pct 是脏页比例上限,默认值是 75%。InnoDB 会根据当前的脏页比例(假设为 M),算出一个范围在 0 到 100 之间的数字

InnoDB 每次写入的日志都有一个序号,当前写入的序号跟 checkpoint 对应的序号之间的差值,我们假设为 N。InnoDB 会根据这个 N 算出一个范围在 0 到 100 之间的数字,这个计算公式可以记为 F2(N)

然后,根据上述算得的 F1(M) 和 F2(N) 两个值,取其中较大的值记为 R,之后引擎就可以按照 innodb_io_capacity 定义的能力乘以 R% 来控制刷脏页的速度。

image-20220612112916781

InnoDB会在后台刷脏页,而刷脏页的过程就是要将内容页写入磁盘。所以,无论是查询语句在需要内存的时候要求淘汰一个脏页,还是由于刷脏页的逻辑会占用IO资源并影响到更新语句,都可能造成业务端感知到抖了一下。

刷新的策略

在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的数据页也还是脏页的话,也会被放到一起刷。

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

# 参考

MySQL 实战 45 讲-极客时间 (opens new window)

#MySQL
上次更新: 2024/06/29, 15:13:44
MySQL深入09-字符串字段加索引
MySQL深入11-数据库表空间回收

← MySQL深入09-字符串字段加索引 MySQL深入11-数据库表空间回收→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式