《redis》之分布式锁
(1)互斥性。在任意时刻,只有一个客户端能持有锁。
(2)不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
(3)加锁和解锁必须是同一个客户端。客户端自己不能把别人加的锁给解了。
SETNX ,可以保证如果已有key存在,则函数不会调用成功,也就是只有一个客户端能持有锁,满足互斥性。
对锁设置过期时间,即使锁的持有者发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。
将value赋值为requestId,代表加锁的客户端请求标识,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。
由于我们只考虑Redis单机部署的场景,所以容错性我们暂不考虑。
SETNX key value
只在键 key
不存在的情况下, 将键 key
的值设置为 value
。
若键 key
已经存在, 则 SETNX
命令不做任何动作。
SETNX
是『SET if Not eXists』(如果不存在,则 SET)的简写。
返回值
命令在设置成功时返回 1
, 设置失败时返回 0
。
加锁和解锁必须是同一个客户端
错误场景
设置锁的过期时间为10s
A用户执行完成需要15秒,执行到10s的时候锁过期,B用户获得锁,B用户执行完成需要8S
当A在执行5S之后,释放锁、释放的是B持有的锁,如此导致锁的失效
解决
通过给value赋值为requestId
原因就是我们在上面讲到可靠性时,分布式锁要满足第四个条件解铃还须系铃人,通过给value赋值为requestId,我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID().toString()
方法生成。
锁的过期时间
启用定时器监视分布式锁,一开始设置锁的过期时间为10S,每过3S就发现任务没有执行完,就重新设置锁的过期时间为10S
redission
优化
100个库存,分成10分,每10分使用一个分布式锁,---》分段锁
主从失效问题
redlock,使用zookeeper