论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
ToB企服应用市场:ToB评测及商务社交产业平台
»
论坛
›
大数据
›
数据仓库与分析
›
MySQL实战45讲 12
MySQL实战45讲 12
宁睿
金牌会员
|
2022-8-31 23:56:53
|
显示全部楼层
|
阅读模式
楼主
主题
812
|
帖子
812
|
积分
2446
12 | 为什么我的MySQL会“抖”一下?
一条 SQL 语句,正常执行的时候特别快,但是
有时也不知道怎么回事,它就会变得特别慢
,并且这样的场景很难复现,它不只随机,而且持续时间还很短。
你的 SQL 语句为什么变“慢”了
内存里的数据写入磁盘的过程,叫做
flush
。在这个 flush 操作执行之前,内存里的数据和磁盘里的是不一致的。
当
内存数据页跟磁盘数据页
内容不一致的时候,我们称这个内存页为“
脏页
”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“
干净页
”。
平时执行很快的更新操作,其实就是在
写内存和日志
,而 MySQL 偶尔“抖”一下的那个瞬间,可能就是在
刷脏页
(flush)
什么情况会引发数据库的 flush 过程
第一种场景是InnoDB 的redo log 写满了。这时候系统会停止所有更新操作,把 checkpoint 往前推进,redo log 留出空间可以继续写。
把 checkpoint 位置从 CP 推进到 CP’,就需要将两个点之间的日志(浅绿色部分),对应的所有脏页都 flush 到磁盘上。之后,图中从 write pos 到 CP’之间就是可以再写入的 redo log 的区域。
第二种场景是系统内存不足。当需要新的内存页,而内存不够用的时候,就要
淘汰一些数据页
,空出内存给别的数据页使用。如果淘汰的是“脏页”,就要先将脏页写到磁盘。
Q:如果直接淘汰内存,下次需要请求该页时,直接从磁盘读入数据页,然后拿 redo log 出来应用效率不好嘛?
A:
如果
刷脏页一定会写盘
,
就保证了每个数据页有两种状态
:
一种是内存里存在,
内存里就肯定是正确的结果
,直接返回;
另一种是内存里没有数据,就可以肯定数据文件上是正确的结果,读入内存后返回。
这样的效率最高。
第三种场景是 MySQL 认为系统“空闲”的时候
第四种场景是 MySQL 正常关闭的情况。这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。
上面四种场景对性能的影响
后两种情景不会太关注“性能”问题,主要来分析前两种场景下的性能问题。
第一种是“redo log 写满了,要 flush 脏页”,这种情况是 InnoDB 要
尽量避免的
。因为出现这种情况的时候,
整个系统就不能再接受更新了
,所有的更新都必须堵住。如果你从监控上看,
这时候更新数会跌为 0
。
第二种是“内存不够用了,要先将脏页写到磁盘”,这种情况其实是
常态
。
InnoDB 用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:
第一种是,还没有使用的;
第二种是,使用了并且是干净页;
第三种是,使用了并且是脏页。
InnoDB 的策略是尽量使用内存,因此对于一个长时间运行的库来说,未被使用的页面很少。
而当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。
这时候只能把最久不使用的数据页
从内存中淘汰掉:
如果要淘汰的是一个干净页,就直接释放出来复用;
但如果是脏页,
就必须将脏页先刷到磁盘,变成干净页后才能复用
。
所以,刷脏页虽然是常态,但是出现
一个查询要淘汰的脏页个数太多
,会导致查询的响应时间明显变长,明显影响性能
所以,InnoDB 需要有
控制脏页比例
的机制,来尽量避免上面的这两种情况。
InnoDB 刷脏页的控制策略
首先,要正确地告诉 InnoDB 所在主机的
IO 能力
,这样 InnoDB 才能知道需要
全力刷脏页的时候,可以刷多快
。通过设置
innodb_io_capacity
这个参数为磁盘的 IOPS 来避免浪费磁盘性能。
毕竟磁盘能力不能只用来刷脏页,还需要服务用户请求。所以接下来,我们就一起看看 InnoDB 怎么控制引擎
按照“全力”的百分比来刷脏页
。
Q:
如果你来设计策略控制刷脏页的速度,会参考哪些因素呢?
A:
如果刷太慢,会出现什么情况?
首先是内存脏页太多,其次是 redo log 写满。
所以,InnoDB 的刷盘速度就是要参考这两个因素:一个是脏页比例,一个是 redo log 写盘速度。
参数 innodb_max_dirty_pages_pct 是
脏页比例上限
,默认值是 75%。
F1:InnoDB 会根据当前的脏页比例(假设为 M),算出一个范围在 0 到 100 之间的F1
F2:InnoDB 每次写入的
日志
都有一个序号,当前写入的序号跟 checkpoint 对应的序号之间的
差值
为 N。InnoDB 会根据这个 N 算出一个范围在 0 到 100 之间的数字F2
根据上述算得的 F1 和 F2两个值,取其中较大的值记为 R,之后引擎就可以按照
innodb_io_capacity
定义的能力乘以
R%
来控制刷脏页的速度。
总结:
合理地设置 innodb_io_capacity 的值,并且
平时要多关注脏页比例,不要让它经常接近 75%
。
一个有趣的策略
一旦一个查询请求需要在执行过程中先 flush 掉一个脏页时,这个查询就可能要比平时慢了。而 MySQL 中的一个机制,可能让你的查询会更慢:
在准备刷一个脏页的时候,
如果这个数据页旁边的数据页刚好是脏页
,就会把这个“邻居”也
带着一起刷掉
;而且这个把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的数据页也还是脏页的话,也会被放到一起刷。
在 InnoDB 中,
innodb_flush_neighbors
参数就是用来控制这个行为的,值为 1 的时候会有上述的“连坐”机制,值为 0 时表示不找邻居,自己刷自己的。
在 MySQL 8.0 中,innodb_flush_neighbors 参数的默认值是 0
Q:一个内存配置为 128GB、innodb_io_capacity 设置为 20000 的大规格实例,正常会建议你将 redo log 设置成 4 个 1GB 的文件。
但如果你在配置的时候不慎将 redo log 设置成了 1 个 100M 的文件,会发生什么情况呢?又为什么会出现这样的情况呢?
A:
每次事务提交都要写 redo log,如果设置太小,很快就会被写满,也就是下面这个图的状态,这个“环”将很快被写满,
write pos 一直追着 CP
。
这时候系统不得不停止所有更新,去推进 checkpoint。
这时,看到的现象是
磁盘压力很小,但是数据库出现间歇性的性能下跌。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
宁睿
金牌会员
这个人很懒什么都没写!
楼主热帖
java前置学习
简单的用Python对手机号进行加密 ...
k8s v-1.20版本部署详细过程[实测可用 ...
【PostgreSQL】PostgreSQL重建与主库不 ...
net core 3.1使用identityServer登录时 ...
Unity 将是驱动 C# 增长的引擎吗 ? ...
基于单片机的压力测控仿真设计(#0024) ...
开源共建 | 中国移动冯江涛:ChunJun( ...
【RocketMQ】消息的存储
离线数仓建设,企业大数据的业务驱动与 ...
标签云
挺好的
服务器
快速回复
返回顶部
返回列表