请教大神,mysql运行突然变特别慢
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请教大神,mysql运行突然变特别慢相关的知识,希望对你有一定的参考价值。
mysql 在崩溃恢复时,会遍历打开所有 ibd 文件的 header page 验证数据字典的准确性,如果 MySQL 中包含了大量表,这个校验过程就会比较耗时。 MySQL 下崩溃恢复确实和表数量有关,表总数越大,崩溃恢复时间越长。另外磁盘 IOPS 也会影响崩溃恢复时间,像这里开发库的 HDD IOPS 较低,因此面对大量的表空间,校验速度就非常缓慢。另外一个发现,MySQL 8 下正常启用时居然也会进行表空间校验,而故障恢复时则会额外再进行一次表空间校验,等于校验了 2 遍。不过 MySQL 8.0 里多了一个特性,即表数量超过 5W 时,会启用多线程扫描,加快表空间校验过程。如何跳过校验MySQL 5.7 下有方法可以跳过崩溃恢复时的表空间校验过程嘛?查阅了资料,方法主要有两种:
1. 配置 innodb_force_recovery可以使 srv_force_recovery != 0 ,那么 validate = false,即可以跳过表空间校验。实际测试的时候设置 innodb_force_recovery =1,也就是强制恢复跳过坏页,就可以跳过校验,然后重启就是正常启动了。通过这种临时方式可以避免崩溃恢复后非常耗时的表空间校验过程,快速启动 MySQL,个人目前暂时未发现有什么隐患。2. 使用共享表空间替代独立表空间这样就不需要打开 N 个 ibd 文件了,只需要打开一个 ibdata 文件即可,大大节省了校验时间。自从听了姜老师讲过使用共享表空间替代独立表空间解决 drop 大表时性能抖动的原理后,感觉共享表空间在很多业务环境下,反而更有优势。
临时冒出另外一种解决想法,即用 GDB 调试崩溃恢复,通过临时修改 validate 变量值让 MySQL 跳过表空间验证过程,然后让 MySQL 正常关闭,重新启动就可以正常启动了。但是实际测试发现,如果以 debug 模式运行,确实可以临时修改 validate 变量,跳过表空间验证过程,但是 debug 模式下代码运行效率大打折扣,反而耗时更长。而以非 debug 模式运行,则无法修改 validate 变量,想法破灭。 参考技术A 数据库慢一般有三种情况
1。逐渐变慢
2。突然变慢
3。不定时变慢
第一种情况 “逐渐变慢”,要建立一个长期的监控机制。比如,写个shell脚本每天的忙时(通常9~10 etc.)定时收集os,network,db的信息, 每个星期出report对收集到的信息进行分析。这些数据的积累,可以决定后期的优化决策,并且可以是DBA说服manager采用自己决策的重要数据。DBA的价值,就在每个星期的report中体现。
第二种情况 “突然变慢”,也是最容易解决的。先从业务的角度看是DB的使用跟以前有何不同,然后做进一步判断。硬件/网络故障通常也会引起DB性能的突然下降。
第一步: 察看DB/OS/NETWORK的系统log, 排除硬件/网络问题
第二步:察看数据库的等待事件,根据等待事件来判断可能出问题的环节。如果, 没有等待事件, 可以排除数据库的问题. 如果有等待时间, 根据不同的等待事件, 来找引起这些事件的根源.
比如latch free等跟SQL parse有关系的等待事件,OS的表现是CPU 的占用率高
db file scattered read等跟SQL disk read有关系的等待时间, OS的表现是iostat可以看到磁盘读写量增加
第三步: 察看os的信息, CPU/IO/MEMORY等.
a. Cpu 的占用率
CPU占用率与数据库性能不成反比. CPU占用率高, 不能说明数据库性能慢. 通常情况, 一个优化很好, 而且业务量确实很大的数据库, CPU的占用率都会高, 而且会平均分布在每个进程上. 反过来, CPU的占用率都会高也不代表数据库性能就好, 要结合数据库的等待事件来判断CPU占用率高是否合理.
如果某个进程的cpu占用高, 肯定是这个进程有问题. 如果,不是oracle的进程, 可以让application察看是否程序有死循环等漏洞. 如果,是oracle的进程, 可以根据pid查找oracle数据字典看看这个进程的发起程序, 正在执行的sql语句, 以及等待事件. 然后, 不同情况使用不同的方法来解决.
b. IO
排除硬件的IO问题, 数据库突然变慢, 一般来说, 都是一个或几个SQL语句引起的.
如果IO很频繁, 可以通过优化disk reads高的TOP SQL来解决. 当然这也是解决IO问题的最笨也是最有效的办法.
OS以及存储的配置也是影响IO的一个重要的原因.
比如, 最常见的HP-unix下异步IO的问题, 如果DBA GROUP没有MLOCK的权限, ORACLE是不使用AIO的. 偏偏OS与DB的两方的admin如果配合不够好地话, 这个配置就很容易给漏掉了.
c. Memory
第二种情况与memory的关系比较小, 只要SGA区配置合理没有变化, 一般来说, 只要不是Application Memory leak, 不会引起突然变慢的现象.
第三种情况 “不定时变慢”, 是最难解决的. 现场出现的问题原因也是五花八门千奇百怪, 最重要的是, 出现慢的现象时, 以最快的速度抓取到最多的信息以供分析. 先写好抓取数据的shell 脚本, 并在现象发生时及时按下回车键
一个例子
数据库突然变慢
背景: 一个新应用上线后, 数据库突然变慢
第一步, 调查新应用
据开发人员讲新应用访问的都是新建立的表, 表的数据量很小, 没有复杂的SQL查询.
查询 v$sqlarea 分别按照disk_reads / buffer_gets / executions 排序, TOP SQL 中没有新应用的SQL. 排除新应用数据库访问照成的性能问题.
第二步, 察看数据库log/ OS log
数据库log中可以看到大量的ORA-7445错误, 以及大量的dump文件. 分析dump文件(时间久了,没有dump文件可参考, 具体细节没法描述下来. ), 发现是新应用通过dblink访问remote DB时生成的dump文件, 应用开发人说没法修改, Oracle也没有相应的patch解决.
OS log中没有错误信息
第三步, 察看statspack report
从wait events中看到,Top event是“buffer busy waits” “db file parallel write” 等于IO相关的等待事件.
从buffer busy waits 的统计信息来看, 是等待data block.
还有些physical reads等信息与从前比没有太多的异常.
Tablespace 的IO reads/writes也没有异常, 但是wait明显增加.
初步确定是IO问题.
第四步, 察看OS的信息
1. top 命令(输出为实验室数据,仅作格式参考)
load averages: 0.05, 0.10, 0.09 10:18:32
307 processes: 304 sleeping, 1 zombie, 1 stopped, 1 on cpu
CPU states: 96.0% idle, 0.3% user, 2.6% kernel, 1.1% iowait, 0.0% swap
Memory: 4096M real, 2660M free, 1396M swap in use, 3013M swap free
PID USERNAME THR PRI NICE SIZE RES STATE TIME CPU COMMAND
11928 a21562 1 0 0 3008K 2496K cpu/1 0:02 1.12% top
14965 mpgj76 4 59 0 10M 3696K sleep 3:09 0.18% view_server
当时现场数据显示:iowait 值与以前相比大很多, 没有异常进程
2. sar –d (输出为实验室数据,仅作格式参考)
SunOS sc19 5.7 Generic_106541-42 sun4u 03/20/08
00:00:00 device %busy avque r+w/s blks/s avwait avserv
sd410 17 0.4 50 1628 0.1 7.1
sd410,a 0 0.0 0 0 0.0 0.0
sd410,b 0 0.0 0 0 0.0 0.0
sd410,c 0 0.0 0 0 0.0 0.0
sd410,g 17 0.4 50 1628 0.1 7.1
当时现场数据显示,放数据文件的设备 avwait, avque, blks/s值偏大
MySQL抖动-为什么偶现突然变慢的问题?
现象
一条SQL
语句,正常执行的时候特别快,但是有时变得特别慢,并且这样的场景很难复现,它不只随机,而且支持时间还很短。
你的SQL
语句为什么变"慢"了
当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存上和磁盘上的数据页的内容就一致了,称为"干净页"。
抖动原因
MySQL
在执行更新语句时,在更新内存写完redo log后,就返回给客户端,本次更新完成,Mysql
会在Redo log内存被写完时以及服务器系统内存不足,亦或是负载较低时,会使用flush刷盘操作,把内存里的数据写入磁盘。MySQL
出现抖动时,可能就是在刷脏页。
触发场景
- Redo log被使用完毕,必须要清空一部分,以便后续操作,在清空之前需要将正确的数据写入到磁盘。
- 系统内存不足,需要新的内存页,而内存不够用时,就要淘汰一些数据页,内存不够用时,就要淘汰一些数据页。
MySQL
在认定系统"空闲"时刷脏页。MySQL
正常关闭时,会把内存的脏页都flush到磁盘上。
上述四种场景对性能的影响
场景3属于MySQL
空闲时的操作,这时系统没什么压力,场景4是数据库在即将关闭时出现,不会太关注性能问题。
场景1是redo log写满了,要flush脏页,这种情况是InnoDB要尽量避免的。因为出现这种情况时,整个系统就不能再接受更新了,所有的更新都必须堵住。如果从监控上看,这时更新数会跌为0。
场景2:内存不够用了,要先将脏页写到磁盘,这种情况其实是常态。InnoDB用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:
- 第一种是,还没有使用的;
- 第二种是,使用了并且是干净页;
- 第三种是,使用了并且是脏页。
InnoDB的策略是尽量使用内存,对于一个长时间运行的库来说,未被使用的页很少。
当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉,如果要淘汰一个干净页,就直接释放出来复用,但是脏数据页就必须将脏页先刷到磁盘,变成干净页后才能复用。
所以,刷脏页虽然是一种常态,但是明显影响性能的有两种:
- 要淘汰的脏页太多
- 日志写满,更新全部堵住,写性能跌为0,这种情况对于敏感业务来说,是不能接受的。
所以,InnoDB 有控制脏页比例的机制和控制redo log
的写盘速度来尽量避免上面的这两种情况。
以上是关于请教大神,mysql运行突然变特别慢的主要内容,如果未能解决你的问题,请参考以下文章