最近在维护线上MySQL数据库时,突然收到监控系统告警:某台数据库服务器的CPU使用率持续超过90%,已经持续了半小时以上。这种异常情况如果不及时处理,轻则导致查询响应变慢,重则可能引发整个数据库的雪崩效应。
通过SSH连接到服务器后,我用top命令确认了CPU使用情况,发现确实是mysqld进程占用了大量CPU资源。这时候需要明确几个关键点:
在我的案例中,所有核心的使用率都比较均衡,user占比在85%以上,这说明确实是MySQL在处理查询消耗了大量计算资源,而不是系统层面的问题。
遇到MySQL CPU高的问题,我通常会按照以下顺序排查:
sql复制SHOW FULL PROCESSLIST;
sql复制SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
sql复制-- 查看哪些SQL消耗最多CPU
SELECT * FROM sys.statement_analysis
ORDER BY avg_latency DESC LIMIT 10;
除了上述基本方法外,还有一些更专业的工具:
这是最常见的原因之一。当查询没有使用合适的索引时,MySQL不得不进行全表扫描,这会消耗大量CPU资源。
典型案例:
排查方法:
sql复制-- 查看表索引情况
SHOW INDEX FROM 表名;
-- 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM users WHERE name LIKE '%张%';
解决方案:
当大量查询因为锁等待而阻塞时,也会表现为CPU使用率高。这是因为这些查询虽然没有真正执行,但仍然占用着连接和资源。
排查方法:
sql复制-- 查看当前锁情况
SHOW ENGINE INNODB STATUS;
-- 查看等待锁的事务
SELECT * FROM sys.innodb_lock_waits;
解决方案:
MySQL的某些配置参数如果设置不当,也会导致CPU使用率异常。
常见配置问题:
优化建议:
sql复制-- 查看当前配置
SHOW VARIABLES LIKE '%buffer%';
SHOW VARIABLES LIKE '%tmp%';
-- 建议根据服务器内存调整
SET GLOBAL join_buffer_size = 256K;
SET GLOBAL sort_buffer_size = 256K;
当并发连接数过多时,MySQL需要花费大量CPU资源在连接管理和上下文切换上。
排查方法:
sql复制-- 查看当前连接数
SHOW STATUS LIKE 'Threads_connected';
-- 查看最大连接数
SHOW VARIABLES LIKE 'max_connections';
解决方案:
现象:
CPU持续90%+,processlist显示大量相同查询
排查过程:
sql复制SELECT * FROM orders WHERE user_id = ? AND status = 'pending'
解决方案:
sql复制ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
效果:
CPU使用率从90%降至30%,查询速度提升10倍
现象:
高峰时段CPU飙升,持续时间短但频繁
排查过程:
解决方案:
sql复制SET GLOBAL sort_buffer_size = 256K;
效果:
CPU峰值降低50%,内存使用更加稳定
ini复制[mysqld]
# 缓冲池大小(总内存的70-80%)
innodb_buffer_pool_size = 12G
# 日志文件大小
innodb_log_file_size = 1G
# 并发线程数
innodb_thread_concurrency = 16
# 刷新方式
innodb_flush_method = O_DIRECT
建议持续监控以下指标:
CPU问题特征:
IO问题特征:
对于暂时无法优化的查询,可以考虑:
在实际工作中,我发现90%的MySQL CPU高问题都可以归结为以下几类:
索引问题(占50%以上):
pt-index-usage分析索引使用情况配置问题(约30%):
连接管理(约15%):
SHOW STATUS LIKE 'Threads_%'监控连接状态其他(5%):
一个实用的技巧是:当CPU突然升高时,立即执行SHOW PROCESSLIST并保存结果,然后每隔5秒执行一次,比较结果可以快速定位问题查询。