naive 版
加锁:
SETNX ${lockName} ${value} # set if not exist
如果不存在则插入成功,返回 1,加锁成功;否则返回 0,加锁失败
解锁:
DEL ${lockName}
问题1
2 个线程 A、B,线程 A 拿到了锁后,宕机了怎么办?谁来释放锁?
解决:使用自动过期机制:
加锁:
SET ${lockName} ${value} EX 10 NX # atomic opreation
解锁:
DEL ${lockName}
问题2
t0 时刻实例1获取到锁,t3 时刻被自动释放(国企),同时实例2获取到锁,t4 时刻实例1再次释放(实例2的锁),实例3又获取到了锁,造成了数据混乱
解决:设置 value 为当前实例线程 id,在解锁时做判断
加锁:
SET ${localName} ${threadId} EX 10 NX
解锁(使用 lua 脚本实现原子性):
current_value = get ${lockName}
if ${threadId} == current_value then
DEL ${lockName}
问题3
锁被自动释放的问题仍然存在
启动一个异步线程(WatchDog),获取到锁成功后启动异步线程,每隔 x 秒对当前锁续期 y 秒,直到锁被释放停止
至此,单机版的 Redis 分布式锁就得到了成功实现