您的位置:首页 > 数据库 > Redis

REDIS 学习(10)流程图解使用redis实现分布式锁

2016-09-28 17:23 357 查看
redis作为集中式缓存,可以通过它来实现分布式锁。

首先用到的redis操作有:

setnx key value:      当key不存在的时候生效并返回1,当已经有此key的时候返回0

getset key value:     设置新值返回旧值,如果之前不存在也设置新值并返回nil

get key:     返回对应的值,没有则返回nil

del key,key1,key2:      删除,返回删除成功的个数

方案1,使用setnx key value来获得锁,del来释放锁






                                           图1

方案1有个问题是,如果获得锁的线程或者进程崩溃了,这个锁将得不到释放

方案2我们增加将值设置为当前时间,引入超时判断






图2

方案2依然有个问题,并发情况下,同时判断锁超时,n0,n1,n2同时del并通过setnx获取锁可能,会n2把n1获取的锁给删除掉。

方案3增加getset 获取旧的时间设置新的时间,这样删除某个超时锁的操作只有一起,其他的获取锁判断会接下来判断锁没有超时。






图3

注意虚线部分,这是之前其他某个博主的做法,就是谁设置了有效时间戳后就认为获取了这个锁。而实线部分我的做法是获取超时锁后就释放掉,然后重新获取锁。两者应该区别不是太大,都是通过getset解决超时锁只进行一次删除的问题。

最后,依然会有个悬而未决的问题,最初获取这个锁的线程或进程,如果在超时后,锁被其他线程或者进程重新获取后,这个线程或者进程如果复活了,也会再次触发释放锁(del)?

所以我认为,del操作应该增加类似版本号的判断,本文例子用它的时间戳即可

2017年2月7日更正:

由于setnx不能设置过期时间,所以通过setnx结合expire的方式在图1中就能实现锁的过期释放策略:

if(setnx(a,'tag') =ok){

   expire a 1;

}

不过set a  tag ex 1 nx就已经实现了setnx+expire这两步操作,设值返回ok,已经存在返回null。由于是一个redis命令所以是原子操作。而且未来的redis版本可能去掉setnx和setex,
因此推荐用set ex nx的方式。当然为了防止假死的线程复活后删除锁,在set 的时候依然可以通过增加本版本号或者使用随机数的方式来处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  分布式 缓存 redis
相关文章推荐