MySQL太慢?试试这些诊断思路和工具

MySQL 慢怎么办html

若是遇到 MySQL 慢的话,你的第一印象是什么,MySQL 数据库若是性能不行,你是如何处理的?前端

我咨询了一些同行, 获得了如下反馈:mysql

  • 第一反应是再试一次linux

  • 第二个反应是优化一下 SQLios

  • 第三个反应是调大 buffer pool,而后开始换硬件了,换一下 SSDgit

  • 最后实在不行了找个搜索引擎搜索一下“MySQL 慢怎么办”。github

若是你们用的是国内的搜索引擎的话,搜索引擎会推荐某某知道或者某某乎, 推荐一些 MySQL 调优经验, 调大参数 A, 调低参数 B, 诸如此类,相似的网站能告诉你 MySQL 慢怎么办。sql

咱们来分析一下这些现象背后隐藏的意义:数据库

  • 若是再试一次可以成功的话, 意味着你可能碰到了不可复现的外界因素的影响,致使 MySQL 会慢。缓存

  • 若是优化 SQL 能解决,就意味着 SQL 的执行复杂度远远大于它的需求复杂度。

  • 若是调大 buffer pool 能解决,就意味着 MySQL 碰到了自身的某些限制。

  • 若是换 SSD 能解决,那么意味着服务器资源受到了必定的限制。

  • 若是须要搜索引擎,意味着调优这事已经变成了玄学。

本文向你们分享我对 MySQL 慢的诊断思路,以及向你们介绍系统观测工具。

MySQL 慢的诊断思路

MySQL 慢的诊断思路,通常会从三个方向来作:

  1. MySQL 内部的观测

  2. 外部资源的观测

  3. 外部需求的改造

下面依次看一下这几个思路。

MySQL 内部观测

经常使用的 MySQL 内部观测手段是这样的:

  • 第一步是 Processlist,看一下哪一个 SQL 压力不太正常;

  • 第二步是 explain,解释一下它的执行计划;

  • 第三步要作 Profilling,若是这个 SQL 能再执行一次的话, 就作一个 Profilling;

  • 高级的 DBA 会直接动用 performance_schema ,MySQL 5.7 之后直接动用 sys_schema,sys_schema 是一个视图,里面有便捷的各种信息,帮助你们来诊断性能;

  • 再高级一点,会动用 innodb_metrics 进行一个对引擎的诊断。

除了这些手段之外,还有一些乱七八糟的手段就不列在这了,这些是常规的 MySQL 内部状态观测的思路。

外部资源观测

这里引用国外一个大神写的文章,标题是《60 秒的快速巡检》(参考连接在文末)。咱们来看一下它在 60 秒以内对服务器到底作了一个什么样的巡检。一共十条命令,下面一条一条来看一下。

  1. uptime,uptime 告诉咱们这个机器活了多久,以及它的平均负载是多少。

  2. dmesg -T | tail,告诉咱们系统日志里边有没有什么报错。

  3. vmstat 1,告诉咱们虚拟内存的状态,页的换进换出有没有问题,swap 有没有使用。

  4. mpstat -P ALL 1,告诉咱们 CPU 压力在各个核上是否是均匀的。

  5. pidstat 1,告诉咱们各个进程的对资源的占用大概是什么样子。

  6. iostat-xz 1,查看 IO 的问题。

  7. free-m 内存使用率;

  8. sar-n DVE 1,

  9. sar-n TCP, ETCP 1,8 和 9 两条按设备网卡设备的维度,看一下网络的消耗状态,以及整体看 TCP 的使用率和错误率是多少。

  10. top,看一下大概的进程和线程的问题。

这个就是对于外部资源的诊断,这十条命令揭示了应该去诊断哪些外部资源。

 

外部需求改造

第三个诊断思路是外部的需求改造,在这里引用了 MySQL 官方文档中的一章,《Examples of Common Queries 》( https://dev.mysql.com/doc/mysql-tutorial-excerpt/5.5/en/examples.html),文档中介绍了常规的 SQL 怎么写, 给出了一些例子。

下面看一下它其中提到的一个例子。

 

这张表有三列,article、dealer、price。它作的事情是从这个表里选取每一个做者最贵的商品列在结果集中,这是它最原始的 SQL,很是符合业务的写法,可是它是个关联子查询。

 

关联子查询成本是很贵的,因此上面的文档会教你快速地把它转成一个非关联子查询,你们能够看到中间的子查询和外边的查询之间是没有关联性的。

 

第三步,会教你们直接把子查询拿掉,而后转成这样一个 SQL,这个就叫业务改造,先后三个 SQL 的成本都不同,把关联子查询拆掉的成本,拆掉之后 SQL 会跑得很是好,但这个 SQL 已经不能良好表义了,只有在诊断到 SQL 成本比较高的状况下才建议你们使用这种方式。

为何它可以把一个关联子查询拆掉?

这背后的原理是关系代数,全部的 SQL 均可以被表达成等价的关系代数式,关系代数式之间有等价关系,这个等价关系经过变换能够把关联子查询拆掉。

总结一下,对于 MySQL 慢的诊断思路以下:

第一,MySQL 自己提供了不少命令来观察 MySQL 自身的各种状态,从上往下检通常能检到 SQL 的问题或者服务器的问题。

第二,从服务器的角度,咱们从巡检的脚本角度入手,服务器的资源就这几种,观测手法也就那么几种,把服务器的资源所有都观察一圈就能够了。

第三,若是实在搞不定,需求方必定要按照数据库容易接受的方式去写 SQL,这个成本会降低的很是快,这个是常规的 MySQL 慢的诊断思路。

下面重点介绍为你们介绍系统观测工具。

系统观测工具介绍

先从诊断思路的讨论切换到系统的观测工具,首先了解什么叫系统观测工具而且看一下它的举例,而后再回到诊断思路上,看看新的工具的引入能为咱们的思路到底带来怎样的改变。

什么叫系统观测工具

这里也参考了一篇外国人写的文档:

https://jvns.ca/blog/2017/07/05/linux-tracing-systems/

把这个文档拆开,中间描述了三件事情:

  • 系统观测工具的数据源来自于哪里;

  • 数据采集过程,由于采集的是系统的运行情况,因此到底如何采集这是一个难点;

  • 应该怎么看数据,是用图来看,仍是用表来看,它就叫数据处理前端。

第一步,咱们来看一下数据源,Linux 给咱们提供的数据源包括操做系统内核态提供的观测点和用户态提供的观测点,MySQL 很早以前就提供了用户态的观测点。

 

第二步,如何把数据抽出来。如下这些工具中你们最熟悉的应该是 perf 和 ftrace,sysdig 也有人在用,其它的可能有所耳闻,这是从操做系统里抽取数据的方法。

 

第三步,数据处理前端,前端经常使用的也是 perf 和 ftrace。若是你们对 perf 很熟悉的话会知道 perf 出来的数据是一个树形的数据,并能够跟这棵树进行交互,好比说: 查看某个函数运行了多久,哪个函数的时间最长,这个是数据处理前端。

 

咱们来对比一下常规的四类系统观测工具:ftrace, perf_events,eBPF 和 Systemtap,这四个工具到底有什么不一样,看看 Linux 为何提供这么多观测工具。

ftrace:ftrace 是 sysfs 中的一个桩,经过这个桩内核提供了一种观测的形式——把想观测的函数签名打到这个桩里,而后操做系统就会提供这个函数运行的情况。ftrace 的结构如左图, 数据处理前端和采集端是 ftrace, 数据源是下面这一堆。

 

perf:经常使用的 perf 的原理是操做系统提供了一个系统调用能够将数据写到一个缓存中, 而后客户端把这些数据端抽取出来而后呈如今显示器上。

 

eBPF:这是本文想重点推荐的。以上两种方案一种是操做系统提供的文件系统上的桩,一种是操做系统提供的系统调用,而 eBPF 是将一段代码直接插到操做系统内核某一个位置上的机制

 

Systemtap:它的原理是将一段 C 的代码编译成一个内核模块,而后将这个模块嵌到内核里边去,它不是由内核提供的一个机制,而是由内核的模块机制提供的一种功能。

 

介绍了这四种观测工具的不一样,你们在选取观测工具的时候就知道应该怎么选。

这四种观测工具对系统伤害最轻的是谁?

对系统伤害最轻的是系统调用,这是系统承诺出来的服务。而后是 ftrace,这是系统在文件系统层面提供的一个口,告诉你能够经过这个口跟系统交互。

对系统侵入性最强的是谁?

对系统侵入性最强的应该是 eBPF,由于它直接将一根代码嵌入到系统里边去作,最不稳定的应该是 System Tap,由于它是系统的一个模块, 又提供了很是复杂的功能。

 

上图是 eBPF 的架构图,eBPF 先将一段程序编译成二进制代码,而后插入到操做系统里,操做系统运行这段代码的时候,将采集到的数据吐到操做系统自己的空间里,而后再作统一返回。

eBPF 结构最核心的部分在于把代码插入到操做系统中运行,它须要作各类安全保护才能完成这一点,因此这也是这个机制复杂的地方。

下面引用一个开源的 eBPF 脚本集 bcc, 快速看一下 eBPF 能作什么, 这些功能都是开箱即用的。

bcc (eBPF 脚本集) 使用举例

MySQL 的请求延迟分析

一个 MySQL 承担了不少业务,上千个并发˙中,哪个 SQL 最慢,到底有哪些 SQL 在一秒以上,除了 slow log 之外,还能够用这种方法来看。

 

这个命令的结果分为三列,它的第一列是请求的延迟,指数级递增,单位是微秒,中间一列是它的命中数,若是有一个请求命中了 64-127 微秒这个区间,命中数会加一,最后一列是它的分布图,它在同一个报告里提供了数值的方式和图的方式,能够很容易看到结果。

对于这台服务器来讲,我下了一个 select 的性能压力,它大部分的请求集中于 64 到 127 微秒之间。这个数据库的性能可能还不错。

 

再来看另一种压力,我下了一个 select+insert 的混合压力在一个数据库里,它的图又变了,它呈现了一个很是好的双峰图,我将两个峰值用另一种颜色标明,这两个峰值的意思是颇有可能有混合压力在一个数据库里,或者是上面的这部分压力是命中了某些缓存,而下面的某些压力是因为没有命中缓存,致使这部分请求更慢一些, 造成另外一个峰值,因此经过这种峰值分析能够看到数据库大概的一个运行状态。

若是能作得更好,你能够抽检本身的数据库而后作环比图,好比今天和昨天一样的时间,一样的业务压力下对数据库的延迟进行分析,若是数据库的延迟峰一直在日后延,就意味着数据库的状态在变得更糟糕一些。这是 bcc 第一个能作的事情,须要再次强调的是它开箱即用直接下载过来就可使用。

MySQL 的慢查询

 

MySQL 自己提供很好的慢查询,为何还要用另一个机制来获取 MySQL 的慢查询呢?

 

MySQL 的慢查询可能很难作,与 MySQL 的慢日志相比, 它能够低成本地完成:

  1. 获取少许慢查询

  2. 获取某种模式的慢查询

  3. 获取某个用户的慢查询

好比说获取少许的慢查询,为何是少许呢?由于不肯定如今的线上延迟是多少,慢查询只开一秒可能日志瞬间就被堆上去,性能就会下来,可是若是慢查询开个十秒左右,没有请求在这个区间命中,因此要一点一点的去调这个值,好比说线上 1% 的最慢的查询可以命中,可是在这个脚本里面,能够取必定区间的最大的几个查询把它拎出来。

经过脚本还能够命中某种模式的慢查询, 好比说咱们只关心 update 的慢查询, 那么获取 select 的结果就没有太大的意义,或者是我必定要获取某一些特定表的相关的查询,我均可以经过脚原本作。

第三种状况,想获取某个用户的慢查询,这个通常对于多租户系统,由于多租户系统只想针对某一个用户进行慢查询分析的时候,这种脚本就比较好用。

VFS 延迟分析

 

 

对 VFS 作延迟分析,这是对数据库进行了一个写压力,能够明显看到一个双峰图,这是写的两个峰,是数据库对于内核的写压力的反馈。

这个意味着什么呢?这个可能意味着由于这部分的写是命中了操做系统文件系统的缓存,而下面这部分写是真正的写穿到设备的,因此他们俩的延迟不同,这是一个典型的双峰图,你们须要把两个峰拆开来去行这样的分析。

换一个说法,若是写压力都集中在这里,而没有第二个峰的状况下,需不须要去更换物理设备?有可能不须要,由于全部的东西都命中了操做系统的缓存。

短生命周期的临时文件检测

这个不必定常见,MySQL 会在某些状况下动用临时表, 若是 SQL 没写好就会建立临时表,这些临时表的生命周期很短,可是量很大,因此必定要写文件而不能内存里。

在这种状况下会对操做系统形成一些压力,而这个压力又不太好诊断,由于临时文件的生存周期短,因此这个脚本能够帮你们提供一个方案,这个方案的结果是这样子。

 

我作了一个临时表,这个临时表活了 5.3 秒左右,因而它展示在了脚本的结果里。若是扫描本身的线上 MySQL 发现这里有大量的东西说明在大量的使用临时表,若是 IO 压力在此时比较大, 就可能受了临时表的影响。

短链接分析

 

好一点的应用都会用链接池,可是咱们不少的时候没有那么好的运气,老碰到那么好的应用,因此常常业务会扔过来大量的短链接。

 

这个例子中, sysbench 上了一个大并发,可是只活了 300 多毫秒,这些链接都只活了 300 多毫秒,反复运行这个 sysbench 就能够将数据库打死,创建一千个链接,300 毫秒之后也会销毁,再创建一千个链接,你的业务就会忽上忽下,经过这个脚本就能够抓到这个压力从哪一个服务器来的,哪一个端口来的,而后把它搞定就能够了。

长链接分析

 

除了短链接分析,还有长链接分析,哪个业务端老在搞个人数据,老在往里写,总在往里读,搞的网络特别慢。

 

能够帮你们提供这样一个视角,它有读有写。

以上几个 bcc 相关的例子都是现成的脚本。bcc 能够观测操做系统的各个方面,好比说若是有东西被 OOM kill 掉了,内存有泄露的也能够看,它基本上是咱们这几年发现的一个宝库,你们直接调用这些脚本就能够完成不少的别人完成不了的分析,它的技术用的是 eBPF,直接在 github 上直接搜就好了。

eBPF 使用方法 / 限制

若是这里边脚本知足不了要求, 那能够本身写。这里介绍一下脚本的写法以及 eBPF 的限制。

拿上面提到过的 MySQL 延迟分析举例,一个 MySQL 上面有一千个 query,这些 query 大概都落在哪一个延迟时间里面那张图,为了完成这个需求, 我须要写两段程序,其中第一段程序是运行在内核里边的程序。

这段程序的逻辑是这样的:

  • 在 query 开始的时候截获一下,让它记录一个时间戳;

  • 请求结束的时候再截获一下记录一个时间戳;

  • 把两个时间戳相减得到一个延迟;

  • 把这个延迟扔到结果集里边去,程序就完成了。

我用结束时间减开始时间,减一下获得一个延迟,而后把延迟扔到一个统计容器里面,这个事就结束了。这是我要写的第一个程序,是嵌到内核里的程序,可是须要一个外壳的程序负责嵌入。

这个外壳程序的逻辑也很是简单,把刚才那段内核的程序嵌到 MySQL 的观测点上,嵌到内核里面去,而后把结果集拿出来,打印出来就结束了,这是如何写一个 eBPF 的脚本,你们惟一须要作的事情就是这两个程序,而后运行一下。

 

这个程序的核心只有 45 行,中间忽略了负责差错处理的一部分。只须要把如今的脚本拿下来抄一抄,改一改就能够完成不少的功能了。

这么好的方法为何不少人不知道呢?

  1. 操做系统内核的限制,这个功能是 Linux 4.4 引进来的,可是在 Linux 4.4 上存在统计的 bug,咱们推荐的是 Linux 4.9+,部分好用的功能是在 4.13+ 上才开放,这个是 eBPF 最大的限制。怎么办呢?只能祝你们长寿吧!活到 Linux 4.x 内核能在生产环境上使用的那一天。

  2. 它的第二个最大的限制是 MySQL 的编译参数,MySQL 虽然在很早的时候已经提供了 dtrace 的观测点,这些观测点是公用的,可是它在默认的编译出来的官方发布的包里边是不带观测点编译的,因此在直接官方发布的二进制的包里边是用不了这个功能的,你们须要本身编译一下。编译的时候须要带这个参数,这个可能也是属于一个比较大的限制。

因此若是你们受到限制,再推荐换一个工具:systemtap。

Linux 2.6 就已经有了,可是它的机制是写一个内核模块,这种机制其实不是特别稳定,它为了解决不是特别稳定的问题增长了若干限制,好比说能在内核中使用的内存大小有限制,采集频率也有限制,对整个内核性能的影响百分比也有限制,在这些限制参数都开起来的状况下,它仍是比较安全的。

可是不少观测功能就必需要把这些限制关掉,一旦关掉内核就不是很稳定,因此这个工具,我没有敢把它的缺点写在上面由于确实是个好的工具,咱们也很难说它的这个缺点是个致命的缺陷,可是不太推荐在生产环境上使用,可是在测试环境上确实是很是好玩的一个工具,若是你们用不了 eBPF 的话能够用 systemtap 来作一些诊断。

相关文章
相关标签/搜索