什么是分布式锁及正确使用redis实现分布式锁
分布式锁
分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。 举个不太恰当的例子:假设共享的资源就是一个房子,里面有各种书,分布式系统就是要进屋看书的人,分布式锁就是保证这个房子只有一个门并且一次只有一个人可以进,而且门只有一把钥匙。然后许多人要去看书,可以,排队,第一个人拿着钥匙把门打开进屋看书并且把门锁上,然后第二个人没有钥匙,那就等着,等第一个出来,然后你在拿着钥匙进去,然后就是以此类推
实现原理
互斥性
保证同一时间只有一个客户端可以拿到锁,也就是可以对共享资源进行操作
安全性
只有加锁的服务才能有解锁权限,也就是不能让a加的锁,bcd都可以解锁,如果都能解锁那分布式锁就没啥意义了
可能出现的情况就是a去查询发现持有锁,就在准备解锁,这时候忽然a持有的锁过期了,然后b去获得锁,因为a锁过期,b拿到锁,这时候a继续执行第二步进行解锁如果不加校验,就将b持有的锁就给删除了
避免死锁
出现死锁就会导致后续的任何服务都拿不到锁,不能再对共享资源进行任何操作了
保证加锁与解锁操作是原子性操作
- 这个其实属于是实现分布式锁的问题,假设a用redis实现分布式锁
假设加锁操作,操作步骤分为两步:
1,设置key set(key,value)2,给key设置过期时间
假设现在a刚实现set后,程序崩了就导致了没给key设置过期时间就导致key一直存在就发生了死锁
如何实现分布式锁
实现分布式锁的方式有很多,只要满足上述条件的都可以实现分布式锁,比如数据库,redis,zookeeper,在这里就先讲一下如何使用redis实现分布式锁
使用redis实现分布式锁
使用redis命令 set key value NX EX max-lock-time 实现加锁
使用redis命令 EVAL 实现解锁
加锁:
Jedis jedis = new Jedis("127.0.0.1", 6379);
private static final String SUCCESS = "OK";
/**
* 加锁操作
* @param key 锁标识
* @param value 客户端标识
* @param timeOut 过期时间
*/
public Boolean lock(String key,String value,Long timeOut){
String var1 = jedis.set(key,value,"NX","EX",timeOut);
if(LOCK_SUCCESS.equals(var1)){
return true;
}
return false;
}
解读:
加锁操作:jedis.set(key,value,"NX","EX",timeOut)【保证加锁的原子操作】
key就是redis的key值作为锁的标识,value在这里作为客户端的标识,只有key-value都比配才有删除锁的权利【保证安全性】
通过timeOut设置过期时间保证不会出现死锁【避免死锁】
NX,EX什么意思?
NX:只有这个key不存才的时候才会进行操作,if not exists;
EX:设置key的过期时间为秒,具体时间由第5个参数决定
解锁
Jedis jedis = new Jedis("127.0.0.1", 6379);
private static final Long UNLOCK_SUCCESS = 1L;
/**
* 解锁操作
* @param key 锁标识
* @param value 客户端标识
* @return
*/
public static Boolean unLock(String key,String value){
String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";
Object var2 = jedis.eval(luaScript,Collections.singletonList(key), Collections.singletonList(value));
if (UNLOCK_SUCCESS == var2) {
return true;
}
return false;
}
解读:
luaScript 这个字符串是个lua脚本,代表的意思是如果根据key拿到的value跟传入的value相同就执行del,否则就返回0【保证安全性】
jedis.eval(String,list,list);这个命令就是去执行lua脚本,KEYS的集合就是第二个参数,ARGV的集合就是第三参数【保证解锁的原子操作】
上述就实现了怎么使用redis去正确的实现分布式锁,但是有个小缺陷就是锁过期时间要设置为多少合适,这个其实还是需要去根据业务场景考量一下的
上面那只是讲了加锁与解锁的操作,试想一下如果在业务中去拿锁如果没有拿到是应该阻塞着一直等待还是直接返回,这个问题其实可以写一个重试机制,根据重试次数和重试时间做一个循环去拿锁,当然这个重试的次数和时间设多少合适,是需要根据自身业务去衡量的
/**
* 重试机制
* @param key 锁标识
* @param value 客户端标识
* @param timeOut 过期时间
* @param retry 重试次数
* @param sleepTime 重试间隔时间
* @return
*/
public Boolean lockRetry(String key,String value,Long timeOut,Integer retry,Long sleepTime){
Boolean flag = false;
try {
for (int i=0;i<retry;i++){
flag = lock(key,value,timeOut);
if(flag){
break;
}
Thread.sleep(sleepTime);
}
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
到这,用redis实现分布式锁就写完了,下次用zookeeper去实现分布式锁,欢迎留言吐槽 txtx
文中set命令详解:http://redisdoc.com/string/set.html
扫码关注我滴公众号啊

什么是分布式锁及正确使用redis实现分布式锁的更多相关文章
- 分布式锁(2) ----- 基于redis的分布式锁
分布式锁系列文章 分布式锁(1) ----- 介绍和基于数据库的分布式锁 分布式锁(2) ----- 基于redis的分布式锁 分布式锁(3) ----- 基于zookeeper的分布式锁 代码:ht ...
- Redis 分布式锁,C#通过Redis实现分布式锁(转)
目录(?)[+] 分布式锁一般有三种实现方式: 可靠性 分布式锁一般有三种实现方式: 1. 数据库乐观锁; 2. 基于Redis的分布式锁; 3. 基于ZooKeeper的分布式锁.本篇博客将介绍 ...
- Redis分布式锁的正确实现方式
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- Redis实现分布式锁的正确姿势
分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Re ...
- Redis实现分布式锁的正确使用方式(java版本)
Redis实现分布式锁的正确使用方式(java版本) 本文使用第三方开源组件Jedis实现Redis客户端,且只考虑Redis服务端单机部署的场景. 分布式锁一般有三种实现方式: 1. 数据库乐观锁: ...
- Redis(十三):Redis分布式锁的正确实现方式
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- Redis分布式锁的正确实现方式(Java版)
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- Redis 分布式锁 - 分布式锁的正确实现方式
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- Redis 分布式锁的正确实现方式(转)
_ 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各 ...
随机推荐
- Windows Mobile和Wince(Windows Embedded CE)的字符集问题
背景 开发过Windows Mobile和Wince(Windows Embedded CE)的开发者,特别是Native C++开发者,或多或少都遇到过ANSI字符集和Unicode字符集的转换问题 ...
- FFMPEG结构体分析:AVCodec
注:写了一系列的结构体的分析的文章,在这里列一个列表: FFMPEG结构体分析:AVFrame FFMPEG结构体分析:AVFormatContext FFMPEG结构体分析:AVCodecConte ...
- Understanding Android Security(安卓安全的理解)
论文作者: Enck, William Ongtang, MacHigar McDaniel, Patrick 下一代的开放操作系统不会在个人主机和大型主机上出现,而是在只能手机上.新环境的开放性将会 ...
- Java-ServletRequestEvent-ServletRequestAttributeEvent
/** * Events of this kind indicate lifecycle * events for a ServletRequest. * The source of the even ...
- iOS 10正式发布:十大新功能,更注重人性化
6月14日凌晨消息,苹果公司举行2016年WWDC全球开发者大会,介绍了watch OS.tv OS.OS X以及iOS 10系统的新特性. 据苹果介绍,iOS 10在锁屏.Siri.地图等十个各方面 ...
- Linux文件内容查阅 - cat, tac, nl, more, less, head, tail, od
cat 由第一行开始显示文件内容 tac 从最后一行开始显示,可以看出 tac 是 cat 的倒著写! nl 显示的时候,顺道输出行号! more 一页一页的显示文件内容 less 与 more 类似 ...
- django-debug-tools 使用
用django开发很快也很容易,但是很多时候我们的经验并不是很足,就会给自己挖下很多坑,不管是性能问题,还是开发语言使用技巧问题都会给应用的稳定带来危害, 开发之后的调试和调优就显得很重要,今天就尝试 ...
- Zeromq自连接错误
Zeromq自连接错误(金庆的专栏)Zeromq消息中间件开发的服务器和客户端不必按顺序启动,客户端可以在服务器开启之前启动.这是Zmq特别好用的一大特性.利用该特性,网游各功能服务器可以任意重启,实 ...
- 和菜鸟一起学linux之DBUS基础学习记录
D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信.它是个3层架构的IPC 系统,包括: 1.函数库libdbus ,用于两个应用程序互相联系和交互消息. 2.一 ...
- 64位ubuntu安装N64模拟器mupen64
我们知道在windows平台下模拟器多如牛毛,N64的模拟器也不例外.而linux下对于想玩N64的童鞋们有啥好办法呢?我通过度娘找到一款开源的N64模拟器mupen64,其官方网址为:http:// ...