大家所推崇的 Redis 分布式锁,真的可以万无一失吗?

我想请分析下,大家所推崇的 Redis 分布式锁,真的可以万无一失吗?
最新回答
接住路过的风

2024-11-25 04:53:45

使用Redis实现分布式锁最简单的方案是使用命令SETNX。SETNX(SET if Not eXist)的使用方式为:SETNX key value,只在键key不存在的情况下,将键key的值设置为value,若键key存在,则SETNX不做任何动作。SETNX在设置成功时返回,设置失败时返回0。当要获取锁时,直接使用SETNX获取锁,当要释放锁时,使用DEL命令删除掉对应的键key即可。
上面这种方案有一个致命问题,就是某个线程在获取锁之后由于某些异常因素(比如宕机)而不能正常的执行解锁操作,那么这个锁就永远释放不掉了。为此,我们可以为这个锁加上一个超时时间。第一时间我们会联想到Redis的EXPIRE命令(EXPIRE key seconds)。但是这里我们不能使用EXPIRE来实现分布式锁,因为它与SETNX一起是两个操作,在这两个操作之间可能会发生异常,从而还是达不到预期的结果

对此,正确的姿势应该是使用“SET key value [EX seconds] [PX milliseconds] [NX|XX]”这个命令。
从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:EX seconds : 将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value 。PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒。 执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value 。NX : 只在键不存在时, 才对键进行设置操作。 执行 SET key value NX 的效果等同于执行 SETNX key value 。XX : 只在键已经存在时, 才对键进行设置操作。

履行 SET key value PX  milliseconds 的后果同等于履行 PSETEX key milliseconds value 。    NX : 只在键不存在时, 才对键停止设置操纵。 履行 SET key value NX 的后果同等于履行 SETNX key value 。    XX : 只在键曾经存在时, 才对键停止设置操纵。举例,咱们须要创立一个散布式锁,而且设置过时时光为10s,那末能够履行以下下令:

这里我们一眼就可以看出问题来:GET和DEL是两个分开的操作,在GET执行之后且在DEL执行之前的间隙是可能会发生异常的。如果我们只要保证解锁的代码是原子性的就能解决问题了。这里我们引入了一种新的方式,就是Lua脚本,解锁的时候还是使用DEL命令来解锁。
修改之后的方案看上去很完美,但实际上还是会有问题。试想一下,某线程A获取了锁并且设置了过期时间为10s,然后在执行业务逻辑的时候耗费了15s,此时线程A获取的锁早已被Redis的过期机制自动释放了。在线程A获取锁并经过10s之后,改锁可能已经被其它线程获取到了。当线程A执行完业务逻辑准备解锁(DEL key)的时候,有可能删除掉的是其它线程已经获取到的锁,总的来说Redis 分布式锁不是那么万无一失的。

校园霸占了我几十年的青春

2024-11-25 05:24:49

基于数据库,如MySQL 基于缓存,如Redis 基于Zookeeper、etcd等。这里先容一下怎样应用缓存(Redis)完成散布式锁。应用Redis完成散布式锁最简略的计划是应用下令SETNX。SETNX(SET if Not eXist)的应用方法为:SETNX key value,只在键key不存在的情形下,将键key的值设置为value,若键key存在,则SETNX不做任何举措。SETNX在设置胜利时前往,设置失利时前往0。
一枕庭前雪

2024-11-25 06:35:14

这个是不一定的,不是所有的锁子都可以万无一失。
北极甜虾

2024-11-25 03:35:26

是某个线程在猎取锁以后因为某些异样要素(比方宕机)而不能畸形的履行解锁操纵,那末这个锁就永久开释不掉了。
沁晚离殇

2024-11-25 01:02:19

无法做到万无一失,因为所有的设计都不是完美的。