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

MySQL 常见三种故障分析思路

原创 Cui Hulong 2025-11-24
396

在MySQL日常使用中,会碰到各种故障,通过下面3个故障,介绍如何快速定位并恢复。

1.MySQL 无响应&Crash

MySQL因为各种各样的原因没有响应,其中可能的原因可以分成以下两类:

  • 主机层:内存升高、CPU升高、磁盘性能和空间不足。
  • MySQL服务层:SQL质量,参数设置不合理,数据表设计不合理,出现锁,并发过多。

1)主机层出现问题常常会直接导致MySQL崩溃或者宕机。排查方法如下。

  • 确定服务器是否崩溃,检查主机是否关机或者重启过uptime命令,message,dmesg。

  • 查看错误日志,或者借助监控或者服务器命令确认MySQL是否存活(命令 ps -ef|grep mysql)。如果服务器同时运行着mysqld_safe守护进程的时候,MySQL会被自动拉起,错误日志也将包含MySQL重启的消息。

  • 查看日志中包含[ERROR]的信息,和对应MySQL发生故障的时间,将会得到MySQL究竟为什么发生故障的原因。这可以解决大多数的MySQL crash故障(内核参数,Limit限制)。

  • 如果得到了大致问题的方向并且确定了原因之后,应该去查看一下这个问题是否是bug造成的,如果是,是否能够通过数据库升级避免这个bug。如果不是需要怎么也样规避这个问题再次发生。

2)MySQL本身的问题往往一开始会造成无响应,hang住,执行SQL很慢,甚至最终导致崩溃。

  • DDL操作会需要元数据锁(Metadata Lock, MDL) 的排它锁,这个锁会阻塞后续所有对该表的操作(包括读和写),导致连接迅速堆积。
  • 长时间SQL语句占用CPU、内存(排序、分组)、磁盘IO,并持有锁。当这种SQL并发量上来时,数据库资源会被迅速榨干,形成“雪崩效应”。
  • 表设计方面是“先天不足”的问题。 包含:数据量过大,无主键,大字段数据,无索引等情况下,一旦业务增长,性能问题会指数级放大。

解决方法:
1.监控一定要到位(包含操作系统和数据库核心指标)和 优化操作系统内核。
2.官网Bug对应的版本升级。
3.表结构合理设置 和 慢SQL优化。

2.内存使用高

MySQL内存使用高问题需要从多个维度信息分析。如:资源配置,参数配置、透明大页、自身内存泄漏,不规范的SQL语句和第三方补助插件等。

1)操作系统的内存检查
#freee -m
如果OOM还未发生,MySQL还在不断的需求内存时,可以看到此时内存已经不足,并且可能已经使用了swap空间。
如果OOM已经发生,MySQL已经crash,并且被mysqld_safe重新拉起,此时内存使用量应该风平浪静。

使用top监控当前内存的使用:

#top
Mem:  132031556k total, 131418864k used,   612692k free,   212104k buffers
Swap: 16777212k total,        0k used, 16777212k free, 14648144k cache
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
14920 mysql     20   0  125g 109g 6164 S  6.6 88.0  27357:08 mysqld

2)查询内存参数配置
通过SQL查询参数分配的内存配置。

mysql>select (@@query_cache_size + @@tmp_table_size + @@innodb_buffer_pool_size + @@innodb_log_buffer_size + (select count(host) from information_schema.processlist)*(@@read_rnd_buffer_size+ @@sort_buffer_size + @@join_buffer_size + @@binlog_cache_size+ @@thread_stack)) / (1024*1024) AS MAX_MEMORY_MB;

MySQL8.0以上版本应除掉query_cache_size:

mysql> select ( @@tmp_table_size + @@innodb_buffer_pool_size + @@innodb_log_buffer_size + (select count(host) from information_schema.processlist)*(@@read_rnd_buffer_size+ @@sort_buffer_size + @@join_buffer_size + @@binlog_cache_size+ @@thread_stack)) / (1024*1024) as MAX_MEMORY_MB;

如果分配的内存本身已经超越了系统内存是很容易造成OOM的,此时需要查出哪些参数设置比较大,适当降低内存分配。

3)查询配置其他参数据文件打开的数量
innodb_buffer_pool在mysql中占有很大的内存部分,调小innodb_buffer_pool_size可以降低OOM问题。innodb_buffer_pool_size为系统内存的50%~60%。如果这些参数设置都很合理,还是出现了OOM的问题,可能的原因是mysql由于MVCC特性,虽然减少了锁的争用,但是保存的表镜像太多(也会出现大量的proccesslist中长时间连接的线程作为佐证)。

# ps -ef|grep mysql
15746是ps -ef|grep mysql查出的mysql进程号

# lsof -p 15746 |grep ibd|wc -l 

此时如果发现lsof -p 15746 |grep ibd|wc -l查询的值较大。应当检查MySQL和文件系统对于打开文件数量的限制:

#ulimit -a open files (-n) 65535 mysql> show variables like '%open_files_limit%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | open_files_limit | 256 | +------------------+-------+ 1 row in set (0.00 sec)

查参数table_open_cache,当打开一个表后会缓存文件描述符:

mysql> show global variables like 'table_open_cache'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | table_open_cache | 4096 | 1 row in set (0.00 sec) mysql> show global status like '%open%tables%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | Open_tables | 276 | | Opened_tables | 307 | +------------------------+-------+ 4 rows in set (0.01 sec)

当缓存中的值open_tables 临近到了 table_open_cache 值的时候,说明表缓存池快满了,但Opened_tables 还在一直增长,这说明还有很多未被缓存的表。

用SHOW OPEN TABLES FROM database_name命令,可以查看table_open_cache中缓存的表:

mysql> show open tables from employees; +-----------+--------------+--------+-------------+ | Database | Table | In_use | Name_locked | +-----------+--------------+--------+-------------+ | employees | departments | 0 | 0 | | employees | salaries | 0 | 0 | | employees | dept_manager | 0 | 0 | | employees | dept_emp | 0 | 0 | | employees | titles | 0 | 0 | | employees | employees | 0 | 0 | +-----------+--------------+--------+-------------+ 6 rows in set (0.02 sec)

In_use显示当前正在使用此表的线程数,如果大于0也意味着此表被锁。
Name_locked只适用于DROP和RENAME,在执行DROP或RENAME时,table_open_cache中的表文件描述符会被移除,所以不会看到除0以外的其他值。

一般在库表比较多的情况下(分库分表)很容易出现内存占用较大的情况。如果要解决根源,还是需要对库表进行拆分。

4)查看是否有除InnoDB引擎外的其他引擎在消耗内存

mysql>select * from information_schema.tables where engine!='innodb' and engine!='performance_schema' and TABLE_SCHEMA !='information_schema';

5)大操作导致内存上升
备份(mysqldump,xtrabackup) 等第三方工具备份导致使用内存上升。load data 批量导入也会导致大量内存。

解决方法:
1.调整参数配置核心内存参数。
2.检查表结构设计合理。
3.备份尽量放到备节点,避开高峰时间。

3. CPU负载升高

在长期运行当中,CPU负载升高,往往是问题SQL往往有order by或group by语句,多表连接造成的性能问题。另外一种情况是QPS很大,即使SQL已经质量足够好,但是由于负载很大。

排查方法:
1)top监控查看CPU高的进程
查看是否是MySQL进程暂居大量内存。同时确认内存是否释放。

#top -H -p 1821
top - 21:04:24 up 10 min,  1 user,  load average: 0.00, 0.02, 0.04
Threads:  31 total,   0 running,  31 sleeping,   0 stopped,   0 zombie
%Cpu(s):  90.0 us,  0.2 sy,  0.0 ni, 99.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1867048 total,   390212 free,  1227176 used,   249660 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.   454824 avail Mem 

根据具体PID,定位问题SQL

SELECT a.THREAD_OS_ID,b.id,b.user,b.host,b.db,b.command,b.time,b.state,b.info FROM performance_schema.threads a,information_schema.processlist b WHERE b.id = a.processlist_id and a.THREAD_OS_ID=<具体pid>;

2)查看执行SQL语句信息
MySQL中执行SHOW FULL PROCESSLIST 查看长时间执行的SQL语句。

mysql> SHOW FULL PROCESSLIST;

找到对应的SQL,进行优化。
当执行完show processlist后出现大量的语句,通常其状态出现sending data,Copying to tmp table,Copying to tmp table on disk,Sorting result, Using filesort 都是sql有性能问题。

  • sending data表示:sql正在从表中查询数据,如果查询条件没有适当的索引,则会导致sql执行时间过长。
  • Copying to tmp table on disk:出现这种状态,通常情况下是由于临时结果集太大,超过了数据库规定的临时内存大小,需要拷贝临时结果集到磁盘上,这个时候需要用户对sql进行优化。
  • Sorting result, Using filesort:出现这种状态,表示sql正在执行排序操作,排序操作都会引起较多的cpu消耗,通常的优化方法会添加适当的索引来消除排序,或者缩小排序的结果集。

解决方法:
1.Explain进行语句的优化。
2.检查表结构设计合理(主键,索引)。
3.备份尽量放到备节点,避开高峰时间。

总结

MySQL故障分析的核心思路:

  • 保持冷静:按既定流程操作
  • 日志先行:错误日志是解决问题的第一把钥匙
  • 分层排查:从应用到硬件逐层排除
  • 工具辅助:善用各种监控和分析工具
  • 经验积累:每次故障都是一次学习机会

掌握这个分析框架和技术点,就能在面对大多数MySQL故障时,做到心中有数,手中有术。

最后修改时间:2025-11-24 17:51:54
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论