马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
MySQL 的 CPU 长期顶到 80% 以上,业务侧的表现就是查询变慢、连接超时、最后直接连不上。定位这类问题有个清晰的思路:先分清是用户线程还是系统线程在吃 CPU,再对号入座——慢查询、计算量大、高 QPS 三类成因,对应的手段完全不同。
一、现象与起点
CPU 利用率超过 80% 时,通常伴随响应变慢、超时甚至无法连接。第一件事不是急着重启或加配置,而是看清楚是哪类线程在忙。
- 用户线程:真正执行 SQL 的线程,繁忙绝大多数由慢查询、计算量大、高 QPS 引起。
- 系统线程:刷脏页、purge、排序这类内部线程。实践中这类出问题较少,可用核数 ≥ 4 时一般也不会跑满,个别 bug 例外。
二、第一条路:慢查询
表现为单条 SQL 长时间占着 CPU,常见于 order by、group by、临时表、join 等重操作。
2.1 看当前在跑什么
mysql> SHOW FULL PROCESSLIST;
输出各列含义:
- Id:线程唯一标识,杀线程要用它。
- User:发起这个线程的用户。
- Host:客户端 IP 与端口,用来定位是哪个机器的哪个进程。
- DB:当前命令作用在哪个库,没指定就是 NULL。
- Command:此刻线程正在执行的命令类型。
- Time:处于当前状态已经多久,排查重点看这个。
- State:线程状态,与 Command 对应。
- Info:执行的语句,默认只显示前 100 字符,要看全必须加 FULL。
mysql> select * from information_schema.processlist where Command != 'Sleep' order by Time desc;
mysql> KILL <id>;
Time 倒序,一眼看出哪些线程跑得最久;确认是慢 SQL 导致 CPU 尖峰,可以先 KILL 掉持续占用不放的线程止血。
2.2 打开慢查询日志
慢日志 记录执行时间超过 long_query_time 且扫描行数不小于 min_examined_row_limit 的语句,默认未开启。long_query_time 默认 10 秒,最小 0,精度可到微秒。Linux 下配置文件一般是 /etc/my.cnf:
slow_query_log=1
long_query_time=2
# 记录执行较慢的管理语句
log_slow_admin_statements=1
# 记录执行较慢的未使用索引的语句
log_queries_not_using_indexes=1
2.3 用 EXPLAIN 看执行计划
EXPLAIN SELECT * FROM table WHERE column = 'value';
重点看 type:出现 ALL(全表扫描)通常意味着索引没用上,是优化的第一切入点。
三、第二条路:计算量大
数据量本来就大,即使索引和执行计划都没毛病,CPU 照样跑满。加上 MySQL 是 one-thread-per-connection 模型,不需要太多并发就能把核吃干。两条常规解法:
- 读写分离:把这类重查询挪到平时业务压力小的只读从库上。
- 程序端拆 SQL:把单个大查询拆成多个小查询,避免一次算出巨大的中间结果。
四、第三条路:高 QPS
单条 SQL 不慢、每个请求占用 CPU 也不多,但总量压过来——比如 4 核机器扛 2 万到 3 万的点查询,QPS 一高 CPU 时间就称满了。三条应对:
- 升 CPU 配置:直接提高单机处理能力。
- 挂只读实例:把读压力分走,主实例专注写。
- 优化查询语句:减少不必要的查询与返回列,从源头降 QPS 压力。
五、一条完整的处置顺序
top / mpstat 确认 MySQL 确实在吃 CPU,且是用户态(us)还是内核态(sy)。
SHOW FULL PROCESSLIST 按 Time 倒序找长跑线程,KILL 掉持续占着的。
- 打开慢日志
+ EXPLAIN 定位具体语句,优先补索引、改写 SQL。
- 如果 SQL 已经没毛病只是量太大:读写分离 / 拆 SQL / 加只读实例 / 升配。
- 观察几天确认曲线回落,再决定是否长期调整参数。
结论
MySQL CPU 打满不要一上来就加机器。先看是慢查询、计算量大还是 QPS 高:慢查询走 SHOW FULL PROCESSLIST 找长跑语句 + 慢日志 + EXPLAIN 补索引;计算量大走读写分离和拆 SQL;高 QPS 才考虑升配或加只读实例。系统线程那条线概率低但别忘了排除。
qidao123.com企服评测-应用市场 编辑提示 |