面试高频:为什么MySQL会抖一下?

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 大家好前面我们大概了解了如何巧妙的给字符串字段加索引提高查询性能。今天我们介绍一下为什么MySQL在查询数据的时候,有些时候会 "抖" 一下

先解释一下抖这个字。有些时候的SQL执行非常快,有些时候执行非常慢。通过explain查看SQL的执行计划还是无用。该走的索引也走了,该优化的细节也优了。那么到底是因为什么所以才导致卡顿一下的呢?

首先介绍一下什么是干净页跟脏页。先把路铺好。


干净页

内存上的数据和磁盘上的数据页的内容一致时,称为 “干净页”。

脏页

内存上的数据和磁盘上的数据页的内容不一致时,称为 “脏页”。

举个例子

举一个干净页跟脏页的例子,这个例子也是前几篇文章举的。一家农村型超市,这个超市没有大城市那种不赊账的规矩。所以农村的超市一般会涉及到赊账。那么如何进行有效的记账呢?我们不可能因为赊了一个人就记一次,那这样的话做事的效率是非常低的。因为每次在记账本上找到那个人的名字都要找很久。所以一般采用的是,会有一个临时纸条,这个纸条夹在一个固定的地方,每当晚上打样的时候,统一把所有纸条上的数据一一归到记账本上。

这样才是大多数超市的真实场景,那么数据库里这些是如何实现的呢?纸条就是redo log!记账本就是磁盘!

如下图所示

  1. 第一个小方格中的内容:当前赊账的数据还没有转移到记账本上。所以内存与磁盘上的数据不一致。这样就是一开始介绍的脏页。
  2. 第二个小方格中的内容:到了晚上或者不忙的时候,掌柜或者老板就把纸条上的数据转移到记账本上。这个过程在数据库中就是flush数据的过程。

综上所述:干净页,脏页大概就是这么一个东西。数据库之所以抖一下,就是因为数据库的内部正在进行flush操作

image.png

图1 超市赊账纸条转移到记账本的过程

那么数据库什么时候才会抖一下呢?什么时候开始flush呢?今天我们详细介绍一下


内存场景

我们介绍场景的时候,还是按照上述例子,先从简单易懂的真实场景,再到数据库抽象的过度!下面四个场景看不懂没关系,我们一一介绍。这篇文章还是比较偏底层介绍的,所以耐心一点,看完之后再回味一下。


纸条满了

第一种场景就是,所有纸条都记满了,这个时候必须放下手里的工作。把纸条上的所有账都转移到记账本上。对应的数据库过程就是。redo log满了。需要把redo log日志上的操作转移到磁盘中。变成真正的数据。


一张纸条满了

第二种场景就是,一张纸条满了,掌柜的不得不再找一张纸条过来,继续记账。对应的数据库流程就是,一页数据写满了,MySQL不得不再开一页进行存放数据。


纸条没满,不忙的时候

第三种场景就是,在超市低峰期的时候,都是比较悠闲的。所以这个时候老板闲着也是闲着,不如把纸条上的账,归到记账本上。对应的数据库流程就是,一段时间没人使用数据库的时候,数据库就会自己把redo log日志更新到磁盘上。


打样时

第四种场景就是,超市晚上打样时,完全没人。掌柜的收尾一天工作的时候把账归到记账本上。对应的数据库流程就是,用户关闭会话的时候。没有连接使用了。数据库也会把redo log更新到磁盘上。


分析

第三种情况与第四种情况都是属于空闲时,系统没什么压力。我们就不做分析了。这里着重分析一下第一种与第二钟情况。

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

一张纸条满了:“内存不够用了,要先将脏页写到磁盘”,这种情况其实是常态。InnoDB 用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:还没有使用的,使用了并且是干净页,使用了并且是脏页。

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

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

所以刷脏页是数据库运行的常态了。那么下面两种情况会影响数据库的运行。也就是一开始我们说的数据库为什么会抖音一下的详细原因:

  1. 一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长;
  2. 日志写满,更新全部堵住,写性能跌为 0,这种情况对敏感业务来说,是不能接受的。

所以MySQL想用的稳定,用的爽就必须控制,刷脏页的时机。以及何时刷脏页,刷多块?


innodb刷脏页策略

这里解决一下何时刷脏页,刷多块的问题

首先,你要正确地告诉 InnoDB 所在主机的 IO 能力,这样 InnoDB 才能知道需要全力刷脏页的时候,可以刷多快。下列是数据库用到的参数,通过他来设置。怎么设置我们下面会介绍的。

show variables like 'innodb_io_capacity'

image.png

innodb_io_capacity 不能过高,也不能过低。过高的话会占用大量内存,会严重影响MySQL的日常使用。如果过低会导致脏页太多。数据跟不上使用。导致写入只能等。


如何设置

首先主要考虑两个因素。一个是脏页比例,一个是redo log写盘速度。

下列参数是控制脏页比例。默认值为75。也就是75%

show variables like 'innodb_max_dirty_pages_pct'

InnoDB 会根据当前的脏页比例(假设为 M),算出一个范围在 0 到 100 之间的数字

InnoDB 每次写入的日志都有一个序号,当前写入的序号跟 checkpoint 对应的序号之间的差值,我们假设为 N。InnoDB 会根据这个 N 算出一个范围在 0 到 100 之间的数字,这个计算公式可以记为 F2(N)。F2(N) 算法比较复杂,你只要知道 N 越大,算出来的值越大就好了。

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

如下图,图中的 F1、F2 就是上面我们通过脏页比例和 redo log 写入速度算出来的两个值。

image.png

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

要尽量避免这种情况,你就要合理地设置 innodb_io_capacity 的值,并且平时要多关注脏页比例,不要让它经常接近 75%。

其中,脏页比例是通过 Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total 得到的,具体的命令参考下面的代码:

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;

下面科普一个有趣的策略。一旦一个查询请求需要在执行过程中先 flush 掉一个脏页时,这个查询就可能要比平时慢了。而 MySQL 中的一个机制,可能让你的查询会更慢:在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的数据页也还是脏页的话,也会被放到一起刷。

紧接着相关联的参数是set innodb_flush_neighbors=1 允许连坐机制set innodb_flush_neighbors=0 不允许连坐机制

这个策略还是比较好的。这个优化在机械硬盘时代是很有意义的,可以减少很多随机 IO。机械硬盘的随机 IOPS 一般只有几百,相同的逻辑操作减少随机 IO 就意味着系统性能的大幅度提升。

而如果使用的是 SSD 这类 IOPS 比较高的设备的话,我就建议你把 innodb_flush_neighbors 的值设置成 0。因为这时候 IOPS 往往不是瓶颈,而“只刷自己”,就能更快地执行完必要的刷脏页操作,减少 SQL 语句响应时间。

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

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
18天前
|
存储 关系型数据库 MySQL
MySQL 三万字精华总结 + 面试100 问,和面试官扯皮绰绰有余
本文详细介绍了MySQL数据库的相关知识和技术要点,包括架构、存储引擎、数据类型、索引、查询、事务和锁机制等内容。以下是简介: 本文从MySQL架构入手,详细讲解了其独特的插件式存储引擎设计,并深入探讨了连接层、服务层、存储引擎层和数据存储层的工作原理。接着,文章对比了常见的存储引擎如InnoDB与MyISAM的特点与应用场景。在数据类型章节,介绍了MySQL支持的主要数据类型及其用途。索引部分则深入剖析了B+树索引的优势及其在InnoDB中的实现细节,并解释了聚簇索引与非聚簇索引的区别。事务章节详细解释了ACID特性和隔离级别的概念,并介绍了MVCC机制。最后,锁机制部分
MySQL 三万字精华总结 + 面试100 问,和面试官扯皮绰绰有余
|
5天前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
6天前
|
SQL 关系型数据库 MySQL
京东面试:什么情况下 mysql RR不能解决幻读? RR隔离mysql如何实现?
老架构师尼恩在其读者交流群中分享了关于MySQL事务隔离级别的深入解析,特别针对RR级隔离如何解决幻读问题进行了详细讨论。文章不仅解释了ACID中的隔离性概念,还列举了四种事务隔离级别(未提交读、提交读、可重复读、串行读)的特点及应用场景。尼恩通过具体的例子和图表,清晰地展示了不同隔离级别下的并发事务问题(脏读、不可重复读、幻读)及其解决方案,特别是RR级隔离下的MVCC机制如何通过快照读和当前读来防止幻读。此外,尼恩还提供了相关面试题的解答技巧和参考资料,帮助读者更好地准备技术面试。更多详细内容和实战案例可在《尼恩Java面试宝典》中找到。
|
16天前
|
SQL 安全 关系型数据库
MySQL 增删操作面试题
MySQL 增删操作面试题
74 1
|
1月前
|
存储 关系型数据库 MySQL
【Java面试题汇总】MySQL数据库篇(2023版)
聚簇索引和非聚簇索引、索引的底层数据结构、B树和B+树、MySQL为什么不用红黑树而用B+树、数据库引擎有哪些、InnoDB的MVCC、乐观锁和悲观锁、ACID、事务隔离级别、MySQL主从同步、MySQL调优
【Java面试题汇总】MySQL数据库篇(2023版)
|
6天前
|
SQL 关系型数据库 MySQL
美团面试:mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)
本文详细解析了MySQL索引失效的多种场景及解决方法,包括破坏最左匹配原则、索引覆盖原则、前缀匹配原则、`ORDER BY`排序不当、`OR`关键字使用不当、索引列上有计算或函数、使用`NOT IN`和`NOT EXISTS`不当、列的比对等。通过实例演示和`EXPLAIN`命令分析,帮助读者深入理解索引失效的原因,并提供相应的优化建议。文章还推荐了《尼恩Java面试宝典》等资源,助力面试者提升技术水平,顺利通过面试。
|
6天前
|
存储 关系型数据库 MySQL
面试官:MySQL一次到底插入多少条数据合适啊?
本文探讨了数据库插入操作的基础知识、批量插入的优势与挑战,以及如何确定合适的插入数据量。通过面试对话的形式,详细解析了单条插入与批量插入的区别,磁盘I/O、内存使用、事务大小和锁策略等关键因素。最后,结合MyBatis框架,提供了实际应用中的批量插入策略和优化建议。希望读者不仅能掌握技术细节,还能理解背后的原理,从而更好地优化数据库性能。
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
14天前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
35 2
|
18天前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
21 0