Redis setnx命令 分布式缓存
setnx命令
将 key 的值设为 value,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是SET if Not eXists的简写。
redis> SETNX mykey “hello”
(integer) 1
redis> SETNX mykey “hello”
(integer) 0
redis> GET mykey
“hello”
getset命令
将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值。
返回给定键 key 的旧值。
如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。
当键 key 存在但不是字符串类型时, 命令返回一个错误。
redis> GETSET db mongodb # 没有旧值,返回 nil
(nil)
redis> GET db
"mongodb"
redis> GETSET db redis # 返回旧值 mongodb
"mongodb"
redis> GET db
"redis"
分布式锁
多个进程执行以下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 删除键的操作以获得锁。
解决上述问题,在del前,进行 getset操作
我们同样假设进程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 操作会导致把其他进程已获得的锁释放掉。
redis分布式锁不火的原因
- 按照上面的死锁,redis非常依赖服务器时间,如果时间设置不一致,就会导致问题
- 现在redis一般为一主多从,如果主机挂了,对上面的 方法也有一系列问题
当然,现在Redis的作者提出了一个更安全的实现,叫做Redlock,但是我们已经习惯使用zk了
参考:
Redis实现分布式锁(setnx、getset、incr)以及如何处理超时情况(一)
Redis setnx命令 分布式缓存的更多相关文章
- 使用Redis SETNX 命令实现分布式锁
基于setnx和getset http://blog.csdn.net/lihao21/article/details/49104695 使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其 ...
- 使用Redis SETNX 命令实现分布式锁(转载)
使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法. SETNX命令简介 命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在. 若 ...
- Redis setNX 实现分布式锁(重复数据插入可用其来实现排他锁)
使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法. SETNX命令简介 命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在. 若 ...
- C#客户端Redis服务器的分布式缓存
介绍 在这篇文章中,我想介绍我知道的一种最紧凑的安装和配置Redis服务器的方式.另外,我想简短地概述一下在.NET / C#客户端下Redis hash(哈希类型)和list(链表)的使用. 在这篇 ...
- Redis SETNX实现分布式锁
1.某进程1执行 SETNX lock 以尝试获取锁 2.由于某进程2已获得了锁,所以进程1执行 SETNX lock 返回0,即获取锁失败 3.进程1执行 GET lock 来检测锁是否已超时,如果 ...
- 分布式缓存技术redis学习系列
分布式缓存技术redis学习系列(一)--redis简介以及linux上的安装以及操作redis问题整理 分布式缓存技术redis学习系列(二)--详细讲解redis数据结构(内存模型)以及常用命令 ...
- springboot+mybatis+redis实现分布式缓存
大家都知道springboot项目都是微服务部署,A服务和B服务分开部署,那么它们如何更新或者获取共有模块的缓存数据,或者给A服务做分布式集群负载,如何确保A服务的所有集群都能同步公共模块的缓存数据, ...
- EhCache+Redis实现分布式缓存
Ehcache集群模式 由于 EhCache 是进程中的缓存系统,一旦将应用部署在集群环境中,每一个节点维护各自的缓存数据,当某个节点对缓存数据进行更新,这些更新的数据无法在其它节点中共享,这不仅会降 ...
- Asp.Net Core 轻松学-正确使用分布式缓存
前言 本来昨天应该更新的,但是由于各种原因,抱歉,让追这个系列的朋友久等了.上一篇文章 在.Net Core 使用缓存和配置依赖策略 讲的是如何使用本地缓存,那么本篇文章就来了解一下如何使用分 ...
随机推荐
- poj 2074
哎怎么说,感觉现在处理平面上点线的题已经比较熟练了. 这题就离散化然后搞个前缀和就没了. 准备开始进一步的自闭了. 下面是disguss的一些样例... 其实是我自己写错了个地方,本来能1A的. #i ...
- VS2015编译rtklib2.4.2
准备工作 在VS2015下新建一个win32的dll项目(空项目) 把在github上下载的rtklib2.4.2里的src文件夹复制到刚刚建立的win32下 把src里的文件添加到项目里,其中头文件 ...
- js中 let 与 var 的区别
一: 变量提升与否 var: console.log(a); // undefined var a = 'abc'; // 这段代码实际执行顺序是: var a; //变量声明提升至当前作用域顶部 c ...
- 五、Java基础加强
Java基础加强 1.MyEclipse的使用工作空间(workspace).工程(project)在eclipse下Java程序的编写和运行,及java运行环境的配置.快捷键的配置,常用快捷键:内容 ...
- 黑盒测试实践——day01
一.任务进展情况 小组成员讨论了测试案例的选取以及测试工具的选取,目前正在设计合理的测试方法,研究待测试系统的功能需求和缺陷. 二.存在的问题 测试工具的使用还是不很清楚. 三.解决方法 通过上网搜集 ...
- Echarts . 在柱状图中添加自定义值 (键值对)
x ["需求"] {"0":"使用Echarts根据数据加载一个饼状图"} {"1":"点击哪个饼状图,弹出此 ...
- C0气体传感器分析
1.外观.价格 2.工作原理 MQ-7 CO气体传感器使用的敏感元件为气敏材料(SnO2),该传感器对一氧化碳的灵敏度高. SnO2在洁净空气中电导率低,传感器的电导率随着空气中CO气体浓度增加而增大 ...
- js--单选按钮赋值
var sex='${userInfo.sex}'; if(sex=="女"){ $("input[name=sex][value='女']").attr(&q ...
- Kali2安装完成后的设置
1.安装中文输入法 vim /etc/apt/sources.list 全部删除,改为国内源 #中科大 deb http://mirrors.ustc.edu.cn/kali kali-rolling ...
- java框架之Hibernate(4)-几种检索方式
准备 模型及映射文件 package com.zze.bean; import java.util.HashSet; import java.util.Set; public class Class ...