分布式锁的实现
满足的条件
互斥性
任意时刻,只有一个客户端持有锁
不会发生死锁
即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
解铃还须系铃人
加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
原子性
加锁和解锁必须具有原子性
步骤
1.多个客户端申请获取锁
即执行多个setnx语句
2.获取成功
即执行setnx语句成功后的客户端,其他客户端等待重试
3.执行业务逻辑
从db获取数据,放入缓存
4.释放锁
执行del语句
总结
以上步骤解决了互斥性
问题一
如果业务逻辑出现异常,导致锁无法释放
解决方案
设置锁的过期时间,解决死锁问题
问题二
在解决问题一后,可能存在释放了其他客户端上的锁,现象如下:
- index1业务逻辑没执行完,3秒后锁被自动释放。
- index2获取到锁,执行业务逻辑,3秒后锁被自动释放。
- index3获取到锁,执行业务逻辑
- index1业务逻辑执行完成,开始调用del释放锁,这时释放的是index3的锁,导致index3的业务只执行1s就被别人释放。
最终等于没锁的情况。
解决方案
setnx获取锁时,设置一个指定的唯一值(例如:uuid);释放前获取这个值,判断是否自己的锁
解决了上锁和释放锁是同一个客户端
问题三
在解决问题二后,删除操作缺乏原子性,现象如下:
可能存在有一个客户端刚好执行到删除del语句,而且已经完成了uuid的判断,但已经过期,此时第二个客户端开始上锁,可恰好第一个客户端开始执行del语句,导致第二个客户端的lock被删除
解决方案
LUA脚本保证删除的原子性
解决了原子性
分布式锁的实现
https://huajframe.github.io/2022/01/20/数据库/非关系型数据库/分布式锁的实现/