线上应用频繁的锁表导致sql超时。

一开始的思路是以为代码里事务没有释放或者循环锁导致的,排查了代码之后没有发现可疑的地方。

查询数据库查看被锁的表 

show OPEN TABLES where In_use > 0; 发现user表频繁被锁

然后看一下是什么进程锁了表

show processlist ;

或者

select * from information_schema.processlist

大概找到了锁表的sql和怀疑是哪个应用在锁表。

然后

SELECT * FROM information_schema.INNODB_TRX;

查询事务的开始和关闭时间

发现表并不是被一直锁死,而是只是锁的很频繁,那为什么涉及update的sql会超时被拒绝呢。

根据同事的建议,怀疑是连接池连接泄露导致的,cobar-client2.2.4以前的版本有一个bug可能会导致连接泄露,

这个bug是在连接异常闪断的情况下异常没有被捕获,导致连接的状态没有被更新,如果异常频繁发生会导致连接池中可用的连接会越来越少,根据方案升级了jar包和加入了配置removeAbandoned removeAbandedTimeout。

但是情况并没有好转,问题难以在开发环境重现,而且是偶发性的,很让人迷惑。

联想到这个问题以前并没有,最近几天才出现的,然后去排查了代码的提交记录,除掉业务代码,涉及数据库配置的修改代码只有一次,几天前修改过一次数据库的地址,当时顺手改了一个配置项maxIdle=60000,本以为是最大空闲连接数,心理还想以前的人怎么把这个值设置的这么大,顺手就给改成100了。最坑的就是这个地方,原来这个在perproties配置文件中叫这个名字,其实在实际datasource的使用中是当作maxWait使用的,从而导致了连接等待时间过短,而且加上maxActive配置数量又偏小,所以并发量稍微一大一点的时候,连接数不够用了等待时间又这么短,就开始报错。

虽然报错信息是:Lock wait timeout exceeded try restarting transaction,但这次问题的原因并不是表被彻底锁死了,是druid连接池的连接数不够用了。

总结:问题的表现一样但是原因可能有很多种,在定位问题的时候要各种情况都排查,各种思路排查,不能只对照着报错信息一条道走到黑,而且一个严重的问题可能就是一次临时起意的小小修改导致的。再者,在变量命名的时要用准确的名字,不然会坑队友,一个变量的名字明明是A你却当作B用很容易坑到别人,虽然逻辑上是没错的但是“约定优于配置”。这种问题一旦被发布到线上环境付出的代价是巨大的。