我的物联网项目(二十七) 分布式锁粗心导致大量阻塞

有天项目中某个业务出现了异常,查询相关日志显示如下:

### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

吓了大跳,居然还有锁时间过长导致后面的业务等待时间较长断开连接抛异常,看了下数据库控制台基本全黄,都是些执行时间较长正在执行的进程。

dddd11.png里面详细的SQL,继续点进去看看执行计划

dddd22.png从执行计划上看,扫码行数其实并不多的,所以还要从具体的业务场景去分析问题。

 

找到执行这条SQL的业务代码,了解当时的业务场景:

t_affairsevent事件表

dddd33.png

简单描述下,这个事件表是用来做分布式事务,利用分布式调度来轮询,然后处理相关业务,具体可以看前面写过 我的物联网项目(八) 简单分布式调度,前面有讲到过利用setNX()来实现分布式锁,每次通过setNX()同一个标识,比如id来抢占锁,前面的业务场景没有问题,但是在这个业务场景里面问题来了,因为同时3个调度来分别执行id为1,2,3的3条记录都可以抢的到,然后都去执行如下SQL:

update t_partner_bymonth set .... where partnerId=10001 ,这样的话会导致多个SQL线程同时在执行同一记录,而且本身update就带锁行,所以导致执行速度巨慢甚至阻塞。

高并发update时,最先获得锁的会优先执行,其它几条处于行锁等待状态,等第一个执行完毕,行锁释放,由下一条语句获取锁进行更新,当其它会话等待的时间达到innodb_lock_wait_timeout(默认是50秒),这些update就会断开,不再执行。

像这种业务场景,将锁标识换成partnerId就可以避免刚才那种情况。

 

 
posted @ 2018-09-05 11:43  心灵之火  阅读(514)  评论(0编辑  收藏  举报