【数据存储篇】Mysql死锁检测与问题
如何避免死锁
设置超时
设置锁等待超时是最为简单粗暴的办法,innodb 提供了加锁阻塞超时时间的设置:innodb_lock_wait_timeout
默认值是 50,即一个加锁请求在等待 50 秒后会自动返回加锁失败
但这样存在几个问题:
该配置项的单位是秒数,因此他的最小粒度是 1 秒,对于有些系统,1 秒的超时显然太长,而另一些系统中,1 秒的超时又显得太短,难以区分是正常的锁等待还是发生了死锁,从而可能造成误伤
主动死锁检测
innodb 提供了主动死锁检测机制,innodb 在锁冲突发生时,会扫描持有该锁或在竞争该锁的事务,判断他们之间是否有可能产生死锁,一旦发现当前事务的等待会产生死锁,那么就会立即返回错误
可以通过 innodb_deadlock_detect 设置为 on 或 off 来开启或关闭主动死锁检测机制,默认是开启状态
看上去主动死锁检测 + 业务重试可以解决所有的死锁问题了,但是这同样存在一定的问题
由于整个主动死锁检测过程需要循环遍历所有持有或等待锁的事务两两间的持有锁情况,所以这个过程的时间复杂度是 O(n^2),在高并发的场景下,例如有 1000 个并发的线程同时更新一行,虽然他们之间并不会产生死锁,但主动死锁检测却要进行 100 万次对比,最终造成 CPU 利用率的飙高