- 厕所占坑原理
已经拿到了 lockvalue ,有了 UUID,但是过期了现在!其他人拿到所锁设置了新值,于是 if 后将别人的锁删了!!也就是删除锁不是原子操作。
- 确保加锁,解锁都原子性。
官方叫做RedLock算法,是Redis官方支持的分布式锁算法.
这个分布式锁有3个重要的考量点
- 互斥(只能有一个客户端获取锁)
- 不能死锁
- 容错(大部分Redis节点或者这个锁就可以加可以释放)
3.1 最普通的实现方式
创建一个key
代码语言:javascript复制SET my:lock 随机值 NX PX 30000
- NX : 只有key不存在的时候才会设置成功
- PX 30000 : 30秒后锁自动释放。别人创建的时候如果发现已经有了就不能加锁了.
释放锁就是删除key,但是一般可以用lua脚本删除,判断value一样才删除:
代码语言:javascript复制关于redis如何执行lua脚本,自行百度
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
为啥用随机值呢? 因为如果某客户端获取锁,但阻塞了很长时间才执行完,此时可能已经超时释放锁了,可能别的客户端已经获取到了锁,要是此时你直接删除key会有问题,所以得用随机值加上面的lua脚本来释放锁.
但是这样是肯定不行的
- 如果是普通的Redis单实例,那就是单点故障
- 是Redis普通主从,那Redis主从异步复制,如果主节点挂了,key还没同步到从节点,此时从节点切换为主节点,别人就会拿到锁.
- Redis最普通的分布式锁的实现原理
3.2 RedLock算法
假设有一个redis cluster,有5个redis master实例. 执行如下步骤获取锁:
- 获取当前时间戳(ms)
- 尝试轮流在每个master节点创建锁,过期时间较短(几十ms)
- 尝试在大多数节点建立一个锁,比如5个节点就要求是3个节点(n / 2 1)
- 客户端计算建立锁的时间,如果建立锁的时间小于超时时间,即建立成功
- 如果锁建立失败,那么就依次删除这个锁
- 只要别人建立了一把分布式锁,就得不断轮询去尝试获取锁