胜日寻芳泗水滨,无边光景一时新。等闲识得东风面,万紫千红总是春 .....
嘟嘟嘟 ....手机响了
接到客服部的保障电话,所有坐席都无法发送消息,系统卡死了....
lz已迅雷不及掩耳盗铃之势检查了服务器的各项资源,发现数据库cpu有点高 ,登录information_schema (Mysql自带的数据库),详情介绍参考十分钟了结MySQL information_schema(https://www.cnblogs.com/shengdimaya/p/6920677.html)
执行sql 命令:
SELECT * FROM `PROCESSLIST` t WHERE t.COMMAND = 'Query' ORDER BY t.TIME desc;
PROCESSLIST这个命令可以查看到mysql 正在执行线程,参数具体描述如下:
ID:连接mysql 服务器线程的唯一标识,进程号,可以通过kill来终止此线程的链接。
User:当前线程连接数据库的用户
Host:显示这个语句是从哪个ip 的哪个端口上发出的。可用来追踪出问题语句的用户
db: 线程连接的数据库,如果没有则为null
Command: 显示当前连接的执行的命令,一般就是休眠或空闲(sleep),查询(query),连接(connect)
Time: 线程处在当前状态的时间,单位是秒
State:显示使用当前连接的sql语句的状态,很重要的列,后续会有所有的状态的描述,请注意,state只是语句执行中的某一个状态,一个 sql语句,已查询为例,可能需要经过copying to tmp table,Sorting result,Sending data等状态才可以完成
Info: 线程执行的sql语句,如果没有语句执行则为null。这个语句可以使客户端发来的执行语句也可以是内部执行的语句
上面简单介绍了一下 processlist命令,继续故障分析:
如上图,发现了这次故障的元凶,有update语句锁表了
LOCK WAIT 55 lock struct(s), heap size 6544, 97 row lock(s)
MySQL thread id 1746505, OS thread handle 0x7f15c7383700, query id 192714382 10.53.158.69 direct_sit Sending data
update cx_etalk_session_relation k inner join (
select
r.id as id
from
cx_etalk_session_relation r, cx_etalk_session_history h
where
r.session_id = h.id and r.send_type = '1' and r.act_direction = '2' and r.is_receive = 'n'
and h.cust_channel = 'app'
and h.tenant_id = 'wandaph'
) m set k.is_receive = 'y' where k.id = m.id
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1560 page no 159381 n bits 112 index `PRIMARY` of table `direct`.`cx_etalk_session_relation` trx id 523767684 lock_mode X locks rec but not gap waiting
通过MySQL执行的sql快速的找到了,原始的sql语句
这条sql 是根据用户手机设备号(deviceNo)去更新用户未读消息的标志位,不知道为啥用户的设备号为空,结果悲剧发生了
于是给开发的新规范又多了一条:禁止在update , delete 语句中使用if动态sql ,必须根据主键来更新跟删除操作