12 | 为什么我的MySQL会“抖”一下?

一、抛砖引玉
一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只随机,而且持续时间还很短。

🏁:1.为什么抖呢?因为MySQL哪个时候可能在刷脏页(flush)。

PS:这里就要提到一个概念了:脏页 && 干净页。

二、正文开始

🏁:2.什么是脏页?干净页?
内存数据页磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容一致了,称为“干净页”

🏁:3.知道了这个概念,那么我们会想什么时候会flush呢?

  1. InnoDB 的 redo log 写满了。这时候系统会停止所有更新操作
  2. 系统内存不足。当需要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用。如果淘汰的是“脏页”,就要先将脏页写到磁盘。
  3. MySQL 认为系统“空闲”的时候
  4. MySQL 正常关闭的情况

思考:第二种情况这里为什么不把内存直接全部淘汰掉,下次访问的时候直接从磁盘加载后通过redo log还原呢?

答:主要是通过性能考虑的,果刷脏页一定会写盘,就保证了每个数据页有两种状态:

  • 一种是内存里存在,内存里就肯定是正确的结果,直接返回;
  • 另一种是内存里没有数据,就可以肯定数据文件上是正确的结果,读入内存后返回。

🏁:4.上述四种场景对性能的影响是什么?(三四情况不用讨论,没影响)。

  • 第一种是“redo log 写满了,要 flush 脏页”,这种情况是 InnoDB 要尽量避免的。因为出现这种情况的时候,整个系统再接受更新了,所有的更新都必须堵住。如果你从监控上看,这时候更新数会跌为 0

  • 第二种是“内存不够用了,要先将脏页写到磁盘”。InnoDB 用缓冲池(buffer pool)管理内存
    🏁:4.1.缓冲池中的内存页有哪三种状态?
    没使用的、使用了但是干净页、使用了是脏页。

👋:正常来讲,而当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉:如果要淘汰的是一个干净页,就直接释放出来复用;但如果是脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用。

到这里我们就明白了,刷脏页是一个必须的过程且可能会影响性能。
比如:一个查询要淘汰脏页太多或者redo log写满强制更新cp时刷脏页

🏁:5.对于性能的影响,InnoDB 脏页的控制策略是什么呢?

  • 用 innodb_io_capacity 控制刷脏页的磁盘IO力度
    ⚠️:默认值是200,如果是SSD这个值建议设置为更大

但是,知道了控制的策略方式,那具体应该如何调控这个刷脏页的速度呢?

⭐️:引擎就按照 innodb_io_capacity 定义的能力乘以 Max(脏页比例, redo log 写入速度)% 来控制刷脏页的速度。并且平时要多关注脏页比例,不要让它经常接近 75%。
PS:脏页比例是通过 Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total

🏁:6.有没有这种可能,你刷脏页越刷变得更慢呢?
在 InnoDB 中,innodb_flush_neighbors 为 1时 这种连坐机制就会让你变得更慢。
PS:在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且可能是多米诺式的。
⚠️:MySQL 8.0 中,innodb_flush_neighbors 参数的默认值已经是 0 了。

三、课后思考
一个内存配置为 128GB、innodb_io_capacity 设置为 20000 的大规格实例,正常会建议你将 redo log 设置成 4 个 1GB 的文件。但如果你在配置的时候不慎将 redo log 设置成了 1 个 100M 的文件,会发生什么情况呢?又为什么会出现这样的情况呢?

四、评论区🐂🍺操作
🏁:7.刷新脏页只是把内存中的脏页写到磁盘中,保持磁盘数据的正确性,这样redo log的数据和 磁盘中的数据 也是一致的,redo log的数据不需要在这个过程中改变,redo log的数据只会在 满了之后,check point点移动的时候改变

🏁:8.redo log记录了undo的变化,undo log buffer也要持久化进undo log,此外,还记录了change buffer的改变,那么还要把change buffer purge到idb
以及merge change buffer.merge生成的数据页也是脏页,也要持久化到磁盘。

🏁:9.innodb是如何知道一个页是不是脏页的?

  • 官方回答
    每个数据页头部有LSN,8字节,每次修改都会变大。 对比这个LSN跟checkpoint 的LSN,比checkpoint小的一定是干净页
    转译:
    buffer pool里维护着一个脏页列表,假设现在redo log 的 checkpoint 记录的 LSN 为 10,现在内存中的一干净页有修改,修改后该页的LSN为12,大于 checkpoint 的LSN,则在写redo log的同时该页也会被标记为脏页记录到脏页列表中,现在内存不足,该页需要被淘汰掉,该页会被刷到磁盘,磁盘中该页的LSN为12,该页也从脏页列表中移除,现在redo log 需要往前推进checkpoint,到LSN为12的这条log时,发现内存中的脏页列表里没有该页,且磁盘上该页的LSN也已经为12,则该页已刷脏,已为干净页,跳过。
    淘汰掉的不一定是脏页,如果是干净页直接就淘汰了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值