分布式锁
- 分布式锁的特性
- 互斥性:任何时刻,对于同一条数据,只有一个应用可以获取到分布式锁
- 高可用性:分布式场景下,一小部分服务器宕机不影响正常使用,以集群方式部署实现分布式锁
- 防止锁超时:客户端如果没有主动释放锁,服务器会在一段时间后自动释放锁,防止客户端宕机或者网络问题导致死锁
- 独占性:加解锁必须由同一台服务器进行,只有锁的持有者才能释放锁
分布式锁的实现
手动实现
锁的获取
SETNX:意为
SET if not exists
,用法SETNX key value
使用时需要添加过期时间,否则如果不进行手动释放,会一直占用锁SET Key 1
EXPIRE key seconds获取锁和设置过期时间分成了两部,不是原子性操作,有可能导致获取锁成功,设置过期时间失败
SETEX:用法
SETEX key seconds value
,将 key 的值设为 value ,并且设置过期时间为 seconds 秒,如果 key 已经存在,则将进行覆盖,类似于以下命令,但是是原子性操作SET key value
EXPIRE key seconds # 设置生存时间PSETEX:用法
PSETEX key milliseconds value
,和SETEX
类似,但是指定过期时间单位为毫秒
锁的释放
- 直接删除 key 即可,但是需要确保当前释放锁的线程是锁的持有者,这个操作需要两个步骤,因此又不是原子性操作了,可以使用 lua 脚本进行拼装,保证操作的原子性
# KEYS[1] 代表当前 key 名称,ARGV[1] 代表线程ID(或其他能识别所属线程的标识)
if redis.call("get",KEYS[1]) == ARGV[1]
then
return redis.call("del",KEYS[1])
else
return 0
end