一、问题排查

由于资源问题,我们很多服务都共用一台机器,某天突发发现vpn登录不正常,连接后闪断频繁,登录机器查看,iowait特别高

通过iotop命令查看发现是mysql进程占用高,造成系统卡顿

二、问题处理

进入mysql,使用show full processlist 可以看到所有链接的情况,但是大多链接的 state 其实是 Sleep 的,这种的其实是空闲状态,没有太多查看价值

我们要观察的是有问题的,所以可以进行过滤:

-- 查询非 Sleep 状态的链接,按消耗时间倒序展示,自己加条件过滤
select id, db, user, host, command, time, state, info
from information_schema.processlist
where command != 'Sleep'
order by time desc; 

这样就过滤出来哪些是正在干活的,然后按照消耗时间倒叙展示,排在最前面的,极大可能就是有问题的链接了,然后查看 info 一列,就能看到具体执行的什么 SQL 语句了,针对分析

展示列解释:

  • id - 线程ID,可以用:kill id; 杀死一个线程,很有用
  • db - 数据库
  • user - 用户
  • host - 连库的主机IP
  • command - 当前执行的命令,比如最常见的:Sleep,Query,Connect 等
  • time - 消耗时间,单位秒,很有用
  • state - 执行状态,比如:Sending data,Sorting for group,Creating tmp table,Locked等等,很有用,其他状态可以看看本文最后的参考文章
  • info - 执行的SQL语句,很有用

kill 使用

上面提到的 线程ID 是可以通过 kill 杀死的;所以上面基本上可以把有问题的执行语句找出来,然后就可以 kill 掉了,那么一个一个来 kill 么?

-- 查询执行时间超过2分钟的线程,然后拼接成 kill 语句
select concat('kill ', id, ';')
from information_schema.processlist
where command != 'Sleep'
and time > 2*60
order by time desc;

在下一步我就不用说了吧,把拼接 kill 的执行结果跑一遍就搞定了

这个有时候非常好用,谁用谁知道,还有个快速的办法,使用以下命令杀死所有进程

mysql -e "show full processlist;" -ss | awk '{print "KILL "$1";"}'| mysql

常见问题

一些问题会导致连锁反应,而且不太好定位,有时候以为是慢查询,很可能是大多时间是在等在CPU、内存资源的释放,所以有时候同一个查询消耗的时间有时候差异很大

总结了一些常见问题:

  • CPU报警:很可能是 SQL 里面有较多的计算导致的
  • 连接数超高:很可能是有慢查询,然后导致很多的查询在排队,排查问题的时候可以看到”事发现场“类似的 SQL 语句一大片,那么有可能是没有索引或者索引不好使,可以用:explain 分析一下 SQL 语句