redis分布式锁的原理

Posted 不积跬步,无以至千里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis分布式锁的原理相关的知识,希望对你有一定的参考价值。

如果让我们自己想办法利用redis命令来实现分布式锁机制,需要怎么做呢?

setnx命令是原子的,在key不存在时创建,创建成功返回true,创建不成功返回false。expire命令可以设置过期时间(防止一直不过期导致死锁)。

但是这两个命令结合在一起使用时,无法保证原子性。有可能expire命令未执行成功时异常退出,导致key没有设置过期时间,从而引发一些错误。

于是,可以借助lua脚本来将多个redis命令封装在一个原子操作里。

现在通常的做法是将exists key,hset key field times,expire key 封装在一起构成加锁操作。这里redis数据类型使用hash不使用String的原因是为了多存储一个加锁次数的字段,为了锁可重入准备的。

因此,通常的基于redis的分布式锁的实现逻辑为:

1 执行加锁的lua脚本:exists,hset,expire等。若exists返回false,继续向下执行,知道加锁成功,若exists返回true,则跳转第二步。

2 判断hash的field字段中是否是当前客户端?若否,则返回key的剩余生存时间,继续循环等待;否则重入锁成功,hincrby key field 1,加锁次数+1。

3 expire生存时间一到,锁会自动释放,key会被删除 del key。

4 client每次unlock,field对应的value值减1,直到减为0,del key。

 

可能存在的问题:

若redis是主从配置,client1在master上加锁成功,此时master同步到slave尚未完成,master挂掉了,然后其它slave竞争为master,此时slave上不存在key,此时client2就能在新的master上加锁成功,

这样就导致了同一个lockkey被两个client同时加锁的情况。

 

怎么解决这个问题呢?

有一个red-lock算法,原理是对所有节点都加锁(而不是只对一个结点加锁),多数通过则成功加锁,否则失败!

应对你提出的场景就是:第一个请求加锁,多数节点通过加锁成功,各节点保存加锁成功信息;

这时主节点挂掉,第二个请求来了,请求加锁,多数节点认为锁已经存在不同意加锁,所以加锁失败,只有等待key失效再次加锁。

以上是关于redis分布式锁的原理的主要内容,如果未能解决你的问题,请参考以下文章

Redis分布式锁的实现原理

Redis分布式锁的实现原理

Redisson实现Redis分布式锁的原理

Redisson实现Redis分布式锁的原理

Redis分布式锁的原理以及如何续期

Redis分布式锁的原理以及如何续期