QPS激增会导致CPU占用升高
分析
可以使用监控工具,查看CPU利用率曲线图和QPS曲线图进行对比。如果CPU曲线图波动情况跟QPS曲线图波动情况基本保持一致,可以明确明确CPU升高时QPS上升导致。反之,CPU曲线图对比QPS曲线图有不同步的峰值抖动,则说明在QPS未明显激增的情况下,CPU占用过高,则大概率跟慢SQL相关,可进行后续慢SQL的排查。
备注:如果没有监控工具协助分析的情况下,可以使用show global status like ‘Questions’ 和show global status like 'Uptime’查询,将两者相除得到就是QPS值。
show global status like 'Questions';
show global status like 'Uptime';
解决QPS激增:
- 判断是否为实际业务激增导致,如果是实际业务激增导致,则可以通过资源扩充,满足业务激增的业务需求;
- 找到具体激增的查询所对应的应用系统的接口,进行限流控制,以保护数据库并发访问量;
- 应用采用读写分离,降低单点访问压力;
- 查看sql是否存在循环插入或者更新的情况,改为批量操作,减少执行次数。
慢SQL会导致CPU升高
分析
通过show processlist查看当前MySQL线程运行情况,主要通过 Time 连接时间和State当前SQL所处的状态来分析慢SQL,一般情况下如果存在Sending data说明该查询较慢,可以将info中的SQL复制出来通过explain查看详细的执行计划进行分析。
show processlist;
可通过MySql自带的慢SQL日志功能分析:
通过root登录数据库开启慢SQL查询日志,set global slow_query_log = ‘ON’,并设置慢SQL过滤时间set global long_query_time = 1(超过1秒视为慢SQL),指定慢SQL日志文件存放路径set global slow_query_log_file = ‘/var/lib/mysql/test_1116.log’。通过持续观察该慢SQL记录日志文件,查找出具体的慢SQL复制出来通过explain查看详细的执行计划进行分析。
解决慢SQL:
- 紧急处理可以先通过杀死对应线程(kill process id),缓解问题;
- 无索引或者索引失效情况下,新建有效索引或者优化SQL语句;
- SQL中有大量聚合操作:简化SQL,将逻辑提炼到业务代码中;聚合操作异步或者预处理;
- SQL返回的数据过多,改为分页查询;
- 读写较多锁竞争激烈,分库分表或读写分离。
大量空闲连接会导致CPU升高
show full processlist;
分析
通过 show full processlist 查看Comand 有大量的Sleep,再根据Time查看装填时间是否很长,如果存在大量长时间睡眠线程占用数据库连接,会导致数据库的吞吐量下降,进而导致阻塞也会引发CPU飘高的现象。
解决:
- 修改MySql配置文件中的 wait_timeout 空闲等待时间,值越小则相对空闲线程就会越少,不过需要重启MySql才会生效;
- 通过 set global wait_timeout = XX 方式热修改该参数。
MySql 问题排查常用命令
Sql执行计划,进行sql执行分析
explain + sql;
explain select * from user;
查看数据库当前执行线程状态
show full processlist;
其中重点字段包括Comand 、Time 、State、Info,可以查看当前所有连接线程中命令、持续时间、状态、对应的SQL信息。
查询当前运行的所有事物
select * from information_schema.INNODB_TRX ;
在执行结果中可以看到是否有表锁等待或者死锁,如果有死锁发生,可以通过下面的命令来杀掉当前运行的事务:KILL trx_mysql_thread_id 。
查看当前出现的锁
select * from information_schema.INNODB_LOCKS;
在改结果中可以看到锁的类型、所属事务ID、锁级别、锁模式等信息。
查看死锁
SELECTb.trx_state,e.state,e.time,d.state AS block_state,d.time AS block_time,a.requesting_trx_id,a.requested_lock_id,b.trx_query,b.trx_mysql_thread_id,a.blocking_trx_id,a.blocking_lock_id,c.trx_query AS block_trx_query,c.trx_mysql_thread_id AS block_trx_mysql_tread_id
FROMinformation_schema.INNODB_LOCK_WAITS aLEFT JOIN information_schema.INNODB_TRX b ON a.requesting_trx_id = b.trx_idLEFT JOIN information_schema.INNODB_TRX c ON a.blocking_trx_id = c.trx_idLEFT JOIN information_schema.PROCESSLIST d ON c.trx_mysql_thread_id = d.idLEFT JOIN information_schema.PROCESSLIST e ON b.trx_mysql_thread_id = e.id
ORDER BYa.requesting_trx_id;
查看InnoDB状态
SHOW ENGINE INNODB STATUS;