开卷故意,好久没写博客了,近期工作也挺忙的。
死锁距离我不遥远。最终还是在高并发时被我碰到了。
DeadLock Found!
虽然编程风格中会尽量避免死锁,可是还是被我碰上了。文章可能看不出来我在做什么事情。仅仅是记录自己的一个排除死锁的过程。
事情起源于两个联动的缓存+redis+异步数据库读写操作。
事务中的这句出现死锁:
DELETE FROM table WHERE FROM key = ‘helloworld’
当初的思考解除死锁的思路例如以下:
1)分析死锁模型,如果1,2 两个线程,如果A,B两个锁,通俗的说 :
1持有A锁。等待B锁 -- 2 持有B锁。等待A锁
于是掐这了,就瘫了。
2)继续思考,要真这么简单,也不好意思称自己project师了,实际开发中都是碰到死锁环。
什么意思呢?继续如果
1持有A。等B,
2持有B,等C,
3持有C。等A
Anyway,读者能够自己如果还有4。5,6。7...
3)继续思考,死锁出现,第一步肯定是重审自己的代码。这个时候一定要对使用的成熟的工具优先保持自信但要保留质疑的态度。怎么重审,记录我的过程
a,我们说代码越简洁,越不easy出错。所以,秉着DRY原则。也要消除反复的代码,能复用就绝对不看着行数而自得。
b。重构过后。一定是要数据层,逻辑层分离。不要在数据层包括逻辑处理。不要在逻辑层去做数据层做的事情。(这个时候会发现,脑中有设计模式思想和没有这个 概念的人是有非常大差别的)
c。回归正题,我代码中的死锁出现是高并发环境,存在热点区。在重构过代码后,肯定要对热点数据进行预处理,才进行异步写入数据库。
什么是热点区?我自己乱 叫的一个名字,就是非常多时候。日志也好,外来数据也好,非常多时候会出现300ms以内出现100条99%相似度的数据。
d,继续測试。发现死锁依然,马上建立新的缓存,推断究竟哪里出了问题。发现,逻辑并没有问题。
e,持着质疑工具的态度,检索使用的工具,高并发发生在异步读写数据库,那么既然逻辑没有问题,读写中操作的数据就不会有问题。那就是数据库这里的锁机制出 了问题。
阅读数据库锁机制文档,发现了事务操作中的页面锁和记录锁出了问题。
f,问题来了。既然是多线程。高并发,就不可能不让事务持有记录锁和页面锁。此时怎么办?
解决的方法。放弃根据索引删除,更新。改用主键进行删除更新操作。
g,測试。正常。
整个过程。看了非常多文档,当中,最实用的:
同一时候也会翻译一篇看到的高并发的国外文章。