暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MYSQL-note10, 数据库抖动

kids and edu 2021-07-21
1355

一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只随机,而且持续时间还很短。这种表现就是数据库突然抖一下。

 

InnoDB 在处理更新语句的时候,只做了写日志这一个磁盘操作。这个日志叫做 redo log(重做日志)。(MySQL 里经常说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘

 

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

 

平时执行很快的更新操作,其实就是在写内存和日志,而 MySQL 偶尔“抖”一下的那个瞬间,可能就是在刷脏页(flush),什么场景触发flush呢

 

1) InnoDB 的 redo log 写满了。这时候系统会停止所有更新操作,把 checkpoint 往前推进,redo log 留出空间可以继续写。(环形)把 checkpoint 位置从 CP 推进到 CP’,就需要将两个点之间的日志,对应的所有脏页都 flush 到磁盘上

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

 

2)系统内存不足。当需要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用。如果淘汰的是“脏页”,就要先将脏页写到磁盘。这里就涉及到innodb刷脏页的控制策略

 

3)MySQL 认为系统“空闲”的时候。合理地安排时间,见缝插针地找时间,只要有机会就刷一点“脏页”。

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

 

 

InnoDB 刷脏页的控制策略

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

 

innodb_io_capacity 的值设置太低,InnoDB 认为这个系统的能力就这么差,所以刷脏页刷得特别慢,甚至比脏页生成的速度还慢,这样就造成了脏页累积,影响了查询和更新性能。现象就是: MySQL 的写入速度很慢,TPS 很低,但是数据库主机的 IO 压力并不大,罪魁祸首就是这个参数的设置出了问题。

 

InnoDB 的刷盘速度就是要参考这两个因素:

1)一个是脏页比例,参数 innodb_max_dirty_pages_pct 是脏页比例上限M,默认值是 75%

2)一个是 redo log 写盘速度。InnoDB 每次写入的日志都有一个序号,当前写入的序号跟 checkpoint 对应的序号之间的差值,假设为 N

M和N可以计算出一个R值,引擎就可以按照 innodb_io_capacity 定义的能力乘以 R% 来控制刷脏页的速度。平时要多关注脏页比例,不要让它经常接近 75%。

 

而 MySQL 中的一个机制:在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个把“邻居”拖下水的逻辑还可以继续蔓延。在 InnoDB 中,innodb_flush_neighbors参数就是用来控制这个行为的,值为 1 的时候会有上述的“连坐”机制,值为 0 时表示不找邻居,自己刷自己的。在 MySQL 8.0 中,innodb_flush_neighbors 参数的默认值已经是 0 了。

 

 

 


文章转载自kids and edu,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论