首页 > 数据库 >redis分布式锁,redis中set和setnx的区别

redis分布式锁,redis中set和setnx的区别

时间:2022-09-22 11:56:02浏览次数:89  
标签:set lock setnx redis 超时 SETNX 进程 foo

转自:https://www.zhangshilong.cn/work/320344.html

 

Redis命令SETNX的使用(包含Java分布式锁实现)

可以参考Redis官网对SETNX命令的介绍:

https://redis.io/commands/setnx

SETNX命令简介

命令格式

SETNX key value

将 key 的值设为 value,当且仅当 key 不存在。 
若给定的 key 已经存在,则 SETNX 不做任何动作。 
SETNX 是SET if Not eXists的简写。

返回值
返回整数,具体为 

 - 1,当 key 的值被设置 
- 0,当 key 的值没被设置

例子

redis> SETNX mykey “hello” 
(integer) 1 
redis> SETNX mykey “hello” 
(integer) 0 
redis> GET mykey 
“hello” 
redis>

使用SETNX实现分布式锁
多个进程执行以下Redis命令:

SETNX lock.foo <current Unix time + lock timeout + 1>

如果 SETNX 返回1,说明该进程获得锁,SETNX将键 lock.foo 的值设置为锁的超时时间(当前时间 + 锁的有效时间)。 
如果 SETNX 返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。

解决死锁
考虑一种情况,如果进程获得锁后,断开了与 Redis 的连接(可能是进程挂掉,或者网络中断),如果没有有效的释放锁的机制,那么其他进程都会处于一直等待的状态,即出现“死锁”。

上面在使用 SETNX 获得锁时,我们将键 lock.foo 的值设置为锁的有效时间,进程获得锁后,其他进程还会不断的检测锁是否已超时,如果超时,那么等待的进程也将有机会获得锁。

然而,锁超时时,我们不能简单地使用 DEL 命令删除键 lock.foo 以释放锁。考虑以下情况,进程P1已经首先获得了锁 lock.foo,然后进程P1挂掉了。进程P2,P3正在不断地检测锁是否已释放或者已超时,执行流程如下:

P2和P3进程读取键 lock.foo 的值,检测锁是否已超时(通过比较当前时间和键 lock.foo 的值来判断是否超时)P2和P3进程发现锁 lock.foo 已超时P2执行 DEL lock.foo命令P2执行 SETNX lock.foo命令,并返回1,即P2获得锁P3执行 DEL lock.foo命令将P2刚刚设置的键 lock.foo 删除(这步是由于P3刚才已检测到锁已超时)P3执行 SETNX lock.foo命令,并返回1,即P3获得锁P2和P3同时获得了锁

从上面的情况可以得知,在检测到锁超时后,进程不能直接简单地执行 DEL 删除键的操作以获得锁。

为了解决上述算法可能出现的多个进程同时获得锁的问题,我们再来看以下的算法。 
我们同样假设进程P1已经首先获得了锁 lock.foo,然后进程P1挂掉了。接下来的情况:

进程P4执行 SETNX lock.foo 以尝试获取锁由于进程P1已获得了锁,所以P4执行 SETNX lock.foo 返回0,即获取锁失败P4执行 GET lock.foo 来检测锁是否已超时,如果没超时,则等待一段时间,再次检测如果P4检测到锁已超时,即当前的时间大于键 lock.foo 的值,P4会执行以下操作 GETSET lock.foo <current Unix timestamp + lock timeout + 1>由于 GETSET 操作在设置键的值的同时,还会返回键的旧值,通过比较键 lock.foo 的旧值是否小于当前时间,可以判断进程是否已获得锁假如另一个进程P5也检测到锁已超时,并在P4之前执行了 GETSET 操作,那么P4的 GETSET 操作返回的是一个大于当前时间的时间戳,这样P4就不会获得锁而继续等待。注意到,即使P4接下来将键 lock.foo 的值设置了比P5设置的更大的值也没影响。

另外,值得注意的是,在进程释放锁,即执行 DEL lock.foo 操作前,需要先判断锁是否已超时。如果锁已超时,那么锁可能已由其他进程获得,这时直接执行 DEL lock.foo 操作会导致把其他进程已获得的锁释放掉。

标签:set,lock,setnx,redis,超时,SETNX,进程,foo
From: https://www.cnblogs.com/rxbook/p/16718739.html

相关文章

  • spring-session-data-redis解决多redis的问题
    1:参考这篇文章就好了https://github.com/yugabyte/redis-code-samples/blob/69fe87302de0c9524036c8476cbc5ed90e988165/spring-session/spring-session-data-redis/src/t......
  • Redis与Python连接实例
    2022-09-221、Redis与Python建立连接之前需要先安装“Redis”安装包:在ubantu中,打开终端,输入命令:sudopipinstallredis此时,是安装Python2.0的版本。一般来说,是将3......
  • CTO 说了:谁再用 Redis 过期监听实现定时任务,立马滚蛋!
    作者:Finley来源:https://www.cnblogs.com/Finley/p/16395466.html前言日前拜读阿牛老师的大作《领导:谁再用定时任务实现关闭订单,立马滚蛋!》发现其方案有若干瑕疵,特此抛......
  • 如何远程访问 Redis
    一、修改配置文件.conf1、将配置文件里面的bind127.0.0.1注释掉,改成#bind127.0.0.1 2、将配置文件里面的protected-modeyes改成protected-modeno 3、在redi......
  • Redis——数据操作(3)
    2022-09-22(4)set操作①添加操作(sadd):例:saddstudentAB②查看操作(smembers):例:smembersstudent③移除操作(srem):例:sremstudentA(5)zset(有序集合......
  • 用Go语言&&redis,如何写分布式锁 ?
    为什么需要分布式锁1因为用户下单,需要锁住uid,防止用户重复下单。2用在库存扣减上,锁住库存,可以防止库存超卖。3用在余额扣减场景,锁住账户,防止并发操作。分布式系统......
  • Redis的持久化方式-RDB
    Redis可以将数据持久化到磁盘里,主要通过两种方式,RDB和AOF的方式存储RDB:在redis里通过save和bgsave命令实现RDB的存储save方式是一种阻塞的方式存储数据bgsave方式是非阻......
  • 1102_REDIS中使用LUA
    定时删除公司费用查询费用并删除数据,保持原子操作准备数据saddsms:send:batchDeduct:company000002sismembersms:send:batchDeduct:company000002hgetallsm......
  • 思考 为什么要用private 为什么要用getter和setter
    有很长一段时间,从入坑Java开始就一直伴随我的问题。既然属性的public权限和带getter/setter的private权限提供的效果一样,为什么还要用private+getter/setter,而不是用public......
  • 【轻量应用服务器】k3s部署redis
    1.在轻应用服务器中安装好K3s2.登录k3s及token 3.登录上k3s,如下图4.按照图下图操作,打开部署界面 5.部署redis,部署用的yaml如下apiVersion:apps/v1kind:Depl......