当前位置: 代码网 > it编程>数据库>Mysql > MySQL数据库CPU飙升到500%的原因和解决方案

MySQL数据库CPU飙升到500%的原因和解决方案

2026年02月28日 Mysql 我要评论
cpu 500%意味着mysql吃掉了好几个核,基本上是某些sql在疯狂消耗计算资源。这种情况下不要急着重启——重启只是把问题藏起来了,过一会儿还会炸。先灭火,再查因,最后防复

cpu 500%意味着mysql吃掉了好几个核,基本上是某些sql在疯狂消耗计算资源。这种情况下不要急着重启——重启只是把问题藏起来了,过一会儿还会炸。

先灭火,再查因,最后防复发。按这个顺序来。

灭火:先找到罪魁祸首

登上服务器,第一件事不是看mysql,是看操作系统。

top -hp $(pidof mysqld)

这条命令列出mysqld进程下所有线程的cpu占用。找到cpu最高的那几个线程,记下它们的lwp(轻量级进程id)。

然后进mysql:

show processlist;

或者更详细的版本:

select id, user, host, db, command, time, state, info 
from information_schema.processlist 
where command != 'sleep' 
order by time desc;

重点看 command 不是sleep的连接——sleep的连接是空闲的,不吃cpu。看 time 列,跑了几百秒甚至几千秒的查询大概率就是凶手。info 列显示正在执行的sql。

找到了问题sql之后,如果业务允许,直接杀掉:

kill <process_id>;

这一步的目的是止血。cpu降下来之后,你才有余裕去分析根因。如果不先杀掉问题查询,服务器可能连登录都卡。

查因:为什么这条sql吃这么多cpu

cpu飙升的原因,90%以上是这几种情况。

全表扫描。 一条查询没走索引,扫了几百万行甚至几千万行。每一行都要从磁盘读到内存(如果buffer pool装不下的话),然后逐行比较where条件。cpu的消耗主要在"逐行比较"这一步。

拿到问题sql之后,用explain看一下:

explain select ... ;

如果 type 列是 allrows 列是几百万,那就是全表扫描。看 key 列是不是null——null说明没用上任何索引。

锁等待引发的连锁反应。 一条慢sql持有行锁,后面的请求全部排队等锁。等待的连接越来越多,每个连接都占一个线程,mysql的线程调度开销就上去了。这种情况下cpu高不是因为在"计算",而是因为在"调度"。

select * from information_schema.innodb_trx 
order by trx_started asc;

这条命令列出所有活跃事务,按开始时间排序。跑了最久的那个事务大概率是罪魁祸首——它持有锁不释放,后面的事务全部堵住了。

select * from performance_schema.data_lock_waits;

这条(mysql 8.0+)能看到谁在等谁的锁。如果 blocking_engine_transaction_id 指向的事务已经跑了很久,考虑杀掉它。

排序和临时表。order bygroup by 的查询,如果排序字段没有索引,mysql会在内存里(或者磁盘上)建临时表做排序。数据量一大,排序本身就是cpu密集型操作。

explain里看到 extra 列有 using filesortusing temporary,就是这个情况。

大量短连接。 某些应用没用连接池,每次请求都新建mysql连接、用完就断开。mysql创建和销毁连接的开销不小(要做认证、分配线程、初始化会话变量)。如果qps很高,光是连接管理就能把cpu吃满。

show global status like 'threads_created';
show global status like 'connections';

如果 threads_created 的值很高且在快速增长,说明在频繁创建新线程。正常情况下,连接池会复用线程,threads_created 应该增长很慢。

常见场景的具体处理

场景一:某条慢sql导致cpu飙升

这是最常见的情况。处理步骤:

杀掉问题查询 → explain分析 → 加索引或改写sql → 验证。

加索引的时候注意:在生产环境给大表加索引,mysql 5.6之前会锁表,5.6之后支持online ddl,但仍然会消耗大量io。如果表有几千万行,加索引可能要跑几分钟到几十分钟,期间会影响写入性能。

建议在业务低峰期操作,或者用 pt-online-schema-change 工具:

pt-online-schema-change --alter "add index idx_user_status(user_id, status)" \
  d=mydb,t=orders --execute

这个工具的原理是创建一张新表、加上索引、通过触发器同步数据、最后原子性地rename。对线上业务的影响比直接alter table小很多。

场景二:大事务持有锁导致连锁堵塞

select trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query
from information_schema.innodb_trx
where trx_started < now() - interval 60 second;

找到跑了超过60秒的事务,看它在干什么。如果是一个忘记提交的事务(trx_query 为null说明当前没在执行sql,但事务还开着),直接杀掉对应的连接:

kill <trx_mysql_thread_id>;

然后去排查应用代码——大概率是某个地方开了事务忘记commit/rollback,或者事务里做了不该做的事(比如在事务里调了外部http接口,接口超时导致事务一直挂着)。

场景三:突发流量导致cpu飙升

不是某条sql有问题,而是正常的sql突然来了十倍的量。这种情况加索引没用,因为每条sql本身都很快,只是量太大了。

短期应对:

set global max_connections = 500;

限制最大连接数,超出的请求直接拒绝,保护mysql不被打死。比让所有请求都卡住要好——至少一部分请求能正常处理。

中期方案:应用层加限流、加缓存。把热点查询的结果缓存到redis,大部分请求不打到mysql。

长期方案:读写分离,读请求分散到从库。

预防:别等cpu飙了再处理

开慢查询日志。 这是最基本的。

set global slow_query_log = 1;
set global long_query_time = 1;

long_query_time 设成1秒。很多人设成10秒,那等于只能抓到"已经严重影响用户体验"的查询。1秒的阈值能让你提前发现潜在问题。

监控线程状态。 定期检查活跃连接数和长时间运行的查询:

select count(*) from information_schema.processlist where command != 'sleep';

活跃连接数突然飙升,往往是cpu飙升的前兆。配合prometheus + grafana做监控告警,活跃连接超过阈值就报警。

定期审查慢查询。 每周跑一次 pt-query-digest,看看有没有新出现的慢查询。很多cpu飙升事故不是突然发生的,而是某条sql随着数据量增长越来越慢,从100ms慢到1秒,从1秒慢到10秒,最后某天数据量过了临界点,直接把cpu打满。

检查buffer pool命中率。

show global status like 'innodb_buffer_pool_read%';

innodb_buffer_pool_read_requests(逻辑读)和 innodb_buffer_pool_reads(物理读,即磁盘读)算 命中率:1 - 物理读/逻辑读。正常应该在99%以上。如果低于95%,说明buffer pool太小,大量数据要从磁盘读,cpu花在io等待上的时间就多了。调大 innodb_buffer_pool_size,一般设成物理内存的60%-80%。

一个容易忽略的点

mysql的cpu飙升有时候不是mysql本身的问题。

检查一下服务器上是不是还跑着别的东西——有些运维图省事,把应用服务和mysql部署在同一台机器上。应用服务突然吃了大量cpu,mysql分到的cpu时间片就少了,本来100ms能跑完的查询变成了500ms,连接堆积,恶性循环。

top 命令看一眼整体cpu分布,如果mysqld不是cpu占用最高的进程,那问题可能根本不在mysql。

还有一种情况是oom killer。linux内核在内存不足的时候会杀掉占内存最多的进程,mysql经常是第一个被杀的。杀完之后mysql重启,buffer pool是冷的,所有查询都要从磁盘读数据,cpu和io同时飙升。看 dmesg | grep -i oom 能确认是不是被oom killer干掉过。

线上数据库出问题的时候,最重要的不是你知道多少优化技巧,而是能不能在压力下保持冷静、按步骤排查。先止血、再查因、最后防复发——这三步的顺序不能乱。cpu飙到500%的时候最怕的操作就是慌了直接重启,重启完发现问题还在,又开始乱改配置,越改越乱。

以上就是mysql数据库cpu飙升到500%的原因和解决方案的详细内容,更多关于mysql cpu飙升到500%的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com