分布式锁的实现

满足的条件

互斥性

任意时刻,只有一个客户端持有锁

不会发生死锁

即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

解铃还须系铃人

加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

原子性

加锁和解锁必须具有原子性

步骤

1.多个客户端申请获取锁

即执行多个setnx语句

2.获取成功

即执行setnx语句成功后的客户端,其他客户端等待重试

3.执行业务逻辑

从db获取数据,放入缓存

4.释放锁

执行del语句

总结

以上步骤解决了互斥性

问题一

如果业务逻辑出现异常,导致锁无法释放

解决方案

设置锁的过期时间,解决死锁问题

问题二

在解决问题一后,可能存在释放了其他客户端上的锁,现象如下:

  1. index1业务逻辑没执行完,3秒后锁被自动释放。
  2. index2获取到锁,执行业务逻辑,3秒后锁被自动释放。
  3. index3获取到锁,执行业务逻辑
  4. index1业务逻辑执行完成,开始调用del释放锁,这时释放的是index3的锁,导致index3的业务只执行1s就被别人释放。

最终等于没锁的情况。

解决方案

setnx获取锁时,设置一个指定的唯一值(例如:uuid);释放前获取这个值,判断是否自己的锁

解决了上锁和释放锁是同一个客户端

问题三

在解决问题二后,删除操作缺乏原子性,现象如下:

可能存在有一个客户端刚好执行到删除del语句,而且已经完成了uuid的判断,但已经过期,此时第二个客户端开始上锁,可恰好第一个客户端开始执行del语句,导致第二个客户端的lock被删除

解决方案

LUA脚本保证删除的原子性

解决了原子性


分布式锁的实现
https://huajframe.github.io/2022/01/20/数据库/非关系型数据库/分布式锁的实现/
作者
HuaJFrame
发布于
2022年1月20日
许可协议