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分布式锁的原理的主要内容,如果未能解决你的问题,请参考以下文章