redis实现分布式锁的目的是什么?使用场景是什么?
在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。
场景2:在理想的情况下,A从任务组中挑选一个任务,任务组删除该任务,B从剩下的的任务中再挑一个。
在真实情况下,如果不做任何处理,可能会出现A和B挑中了同一个任务的情况。
用Redis来实现分布式锁最简单的方式就是在实例里创建一个键值,当一个客户端想要释放锁时,它只需要删除这个键值即可。
通过redis的set命令, 要获取到锁之后才能往下执行。nx项表示not exist。当key不存在的时候才设置
首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
互斥性。在任意时刻,只有一个客户端能持有锁。
不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
加锁就一行代码:jedis.set(String key, String value, String nxxx, String expx, int time),这个set()方法一共有五个形参:
第一个为key,我们使用key来当锁,因为key是唯一的。
第二个为value,我们传的是requestId,原因就是我们在上面讲到可靠性时,分布式锁要满足第四个条件解铃还须系铃人,通过给value赋值为requestId,我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据
第三个参数是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;
第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。
第五个为time,与第四个参数相呼应,代表key的过期时间
首先,set()加入了NX参数,可以保证如果已有key存在,也就是只有一个客户端能持有锁,满足互斥性。
其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。
最后,因为我们将value赋值为requestId,代表加锁的客户端请求标识,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。
由于我们只考虑Redis单机部署的场景,所以容错性我们暂不考虑。
通过执行一个lua脚本, 使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId
只有当值为当前requestId时,才del。保证解锁还需加锁人。
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end;
过期时间一般要设置的比正常执行业务的时间大一些,如果正常执行业务需要1秒,那我设置5秒都是可以的。
因为正常时,用好了就会马上解锁的,不会等到过期时间到了才解锁。
设置过期时间只是为了应对异常情况。正常代码崩掉后,锁释放不了了,就利用过期时间来“兜底”释放。
在redis不会宕机的情况下,上面的单台的方案具有一定的可靠性。
http://ifeve.com/redis-lock/
http://www.importnew.com/27477.html