GreatSQL社区

搜索

李宁ning

应用系统时不时的有锁发生分析

李宁ning 已有 1128 次阅读2022-8-30 11:15 |系统分类:运维实战

现象

Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

自动提交

mysql> show variables like '%commit%';
+-----------------------------------------+-------------------+
| Variable_name                           | Value             |
+-----------------------------------------+-------------------+
| autocommit                              | ON                |

关键是找头锁,阻塞源头。否则开发总是问你为shong么。谁阻塞了谁,怎么就阻塞了。

收集到的信息

方法一:(是的,还有方法2和方法3)

结论:通过blocking_pid 找源头,一般blocking_pid为空的就是没有被阻塞的,没有被阻塞的就是源头喽。

select * from sys.innodb_lock_waits\G

查看blocking在做啥

select * from information_schema.processlist where id in (select blocking_pid from sys.innodb_lock_waits )\G

*************************** 1. row ***************************

 ID: 4208595

USER: hcbm

HOST: 10.206.160.52:40182

DB: hcbm_contract

COMMAND: Sleep

TIME: 132

STATE:

INFO: NULL

竟然是Sleep,睡着了?为什么睡着了还能阻塞别人?活动时间是132秒了,且time在持续增加。只是info空了,说明SQL已经执行完成了。我的慢日志是3秒,在慢日志中没有看到慢SQL,那么肯定SQL执行不慢。那就是没有提交了,至于为什么没有提交只能找开发了。

可能会问为什么他就不是被阻塞造成的无法提交呢?总结呗,遇到百八十次lock wait timeout再配合做实验就知道了,被阻塞的state状态如下,是updating的。delete执行了11秒,状态updating,并且他的语句是会被显示出来的。


方法2的结论:通过对所有有锁的事务按照time时间排序,一般执行时间最长的就是头锁喽,只要kill他基本就能解决问题(是否可以kill找开发)。但是有的时候头锁不只是一个。(SQL内容自己想)

方法3的结论:查看未提交的事务进行排序。总之都是要排序(SQL内容自己想)

下面开始找证据,通过脚本解析binlog

sh /tmp/summarize_binlogs.sh >> /tmp/summarize_binlogs.log  这个时间是我们通过sys.innodb_lock_waits查询出来的时间

找出事务大于200秒的$19>200

cat /tmp/summarize_binlogs.log|grep Transaction|awk '{if($19>200)print}'

不好意思,找出来的大事务就没有截图了(cat出来的结果mysqldba都知道啥意思),然后再通过解析全量的binlog来对应找到完整的事务,从begin到commit,拿给开发甩他脸上。

这个大事务怎么和上面的锁结合起来?

cat出来的大事务也就有几个,这几个xid从全量解析的binlog中搜索,对比下thread_id,并且binglog里有时间#220809 15:34:00,通过执行SQL的时间以及 sys.innodb_lock_waits查询出的waiting_trx_started时间进行对比,或者information_schema.processlist收集到的信息,我当时看到这个是一致的,并且时间在15点30到15点40之间。这个长事务就是上面Sleep线程执行的SQL。这个SQL抓出来后很简单就是一个update,手动执行很快。应该是开发在哪里事务套了事务

下面是脚本summarize_binlogs.sh。此脚本来自运维内参

特别鸣谢范博施

注意:脚本执行较慢,时间越精确越好,10分钟以内,也可能是我的服务器不好。

cat summarize_binlogs.sh
#!/bin/bash
BINLOG_FILE="master-bin.000196"
START_TIME="2022-08-09 15:00:10"
STOP_TIME="2022-08-09 16:00:00"
mysqlbinlog --base64-output=decode-rows -vv --start-datetime="${START_TIME}"  --stop-datetime="${STOP_TIME}" ${BINLOG_FILE} | awk \
'BEGIN {xid="null";s_type=""; stm="";endtm="";intsta=0;inttal=0;s_count=0;count=0;insert_count=0;update_count=0;delete_count=0;flag=0;bf=0;period=0;} \
{
if (match($0,/^(BEGIN)/)) {bg=1;} \
if (match($0,/#.*server id/)) {if(bg==1){statm=substr($1,2,6)" "$2;cmd=sprintf("date -d \"%s\" +%%s", statm);cmd|getline intsta;close(cmd);bg=0;bf=1;}else if(bf==1){endtm=substr($1,2,6)" "$2;cmd=sprintf("date -d \"%s\" +%%s", endtm);cmd|getline inttal;close(cmd);}} \
if(match($0, /#.*Table_map:.*mapped to number/)) {printf "Timestamp : " $1 " " $2 " Table : " $(NF-4); flag=1} \
else if (match($0, /#.*Xid =.*/)) {xid=$(NF)} \
else if (match($0, /(### INSERT INTO .*..*)/)) {count=count+1;insert_count=insert_count+1;s_type="INSERT"; s_count=s_count+1;}  \
else if (match($0, /(### UPDATE .*..*)/)) {count=count+1;update_count=update_count+1;s_type="UPDATE"; s_count=s_count+1;} \
else if (match($0, /(### DELETE FROM .*..*)/)) {count=count+1;delete_count=delete_count+1;s_type="DELETE"; s_count=s_count+1;}  \
else if (match($0, /^(# at) /) && flag==1 && s_count>0) {print " Query Type : "s_type " " s_count " row(s) affected" ;s_type=""; s_count=0; }  \
else if (match($0, /^(COMMIT)/)) {period=inttal-intsta;if(inttal==0){period=0};print "[Transaction total : " count " Insert(s) : " insert_count " Update(s) : " update_count " Delete(s) : " \
delete_count " Xid : "xid" period : "period" ] \n+----------------------+----------------------+----------------------+----------------------+"; \
count=0;insert_count=0;update_count=0; delete_count=0;s_type=""; s_count=0; flag=0;bf=0;bg=0;} } '


















评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

合作电话:010-64087828

社区邮箱:greatsql@greatdb.com

社区公众号
社区小助手
QQ群
GMT+8, 2026-4-16 01:37 , Processed in 0.038150 second(s), 9 queries , Redis On.
返回顶部