Redis优雅实现分布式锁
文章原创于公众号:程序猿周先森。本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号。

在实际项目开发中经常会遇到这样一个业务场景:如果同一台机器有多个线程抢夺同一个共享资源,同一个线程多次执行会出现异常,这种情况下就会出现非线程安全。我们解决方法通常使用锁来解决。但是如果有多台机器呢?这时候我们通常使用分布式锁来解决分布式环境下共享资源的同步问题。实现分布式锁常见有Redis,zookeeper等,今天主要就是讲讲如何使用Redis实现分布式锁。

使用Redis实现分布式锁的方案其实很简单,首先我们先实现一个方案一:每次执行请求的时候,机器先查询Redis中是否存在分布式锁的key,如果不存在锁的key,就以该锁为key,value取随机数写入到Redis中,然后开始执行请求。
方案一看起来很简单,但是这样的处理逻辑不可避免的存在两个致命的BUG:第一:如果一个进程成功取到锁,但是这时候这个机器出现故障宕机了,分布式的锁没有得到释放,就造成了死锁的产生了。第二:如果同一时间存在两个机器同时查询Redis,都发现Redis不存在锁的key,于是都成功获得了锁。
这时候我们可以这么处理改善方案一实现方案二:Redis有提供一个原子写入操作的命令:setnx,setnx只有在锁的key不存在的情况下才允许设置key值,所以说问题2同一个锁在同一时间可能会被不同机器获取到的问题就可以得到解决,而且setnx命令可以设置key值的超时时间,所以在写入锁的key时可以为锁设置一个超时时间,如果超过超时时间锁还未释放就会释放,则其他机器在key释放后也可以继续写入key占有锁执行对应的请求。这样问题1机器宕机造成锁无法及时释放的问题也因此迎刃而解。
但是这又造成了另外一个潜在的问题:如果某个机器执行耗时操作,超时时间过去了请求还未执行完,锁就会被释放掉被新的机器占有,等耗时任务结束时执行释放锁的操作,这时候释放的锁不是自己的锁而是已经被其他机器占有的锁。
这时候我们可以将方案再做适当的修改变成方案三:当某个机器占有锁并在Redis中设置key时,将value设置为随机数,在请求处理完毕需要释放锁之前加上一步操作:判断key的value值是否等于之前设置的随机数,如果是代表这个锁占有者还是自己,就可以执行释放锁操作,否则代表锁已经被别人占有,不能执行释放锁操作,这样就可以解决可能误操作释放他人锁的问题。但是由于查询和释放锁的操作非原子性的,所以可能出现一种情况:在查询key时发现key的value和机器本身设置的一直,但是还没来得急释放锁时,锁过期被释放了,这时候执行释放锁操作就会导致释放的依旧是其他机器占有的锁,所以我们方案三需要进一步的改进,也就是我们必须要保证查询锁和释放锁这两步操作必须是原子性的,这时候我们就需要使用另一种方式:引入Jedis,使用Lua脚本将查询锁和释放锁的两部分逻辑写成脚本,于是Redis执行Lua脚本时,其他机器的所有命令都必须等到Lua脚本执行结束才能执行,所以不可能存在查询锁结束还未释放就被其他机器占领的情况。
到这里我们介绍完了如何使用Redis实现分布式锁,但是这是基于单机部署,如果Redis是使用多机部署,每个主节点还有有子节点,由于Redis主从复制是异步操作,所在上述方案肯定会出现问题的,多机部署可以采用Redission实现分布式锁,这是官方提供的组件,如果感兴趣可以自己阅读下文档:
https://github.com/redisson/redisson
欢迎关注公众号:程序猿周先森

Redis优雅实现分布式锁的更多相关文章
- 基于redis实现的分布式锁
基于redis实现的分布式锁 我们知道,在多线程环境中,锁是实现共享资源互斥访问的重要机制,以保证任何时刻只有一个线程在访问共享资源.锁的基本原理是:用一个状态值表示锁,对锁的占用和释放通过状态值来标 ...
- 一个Redis实现的分布式锁
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.conne ...
- 基于Redis的简单分布式锁的原理
参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的 ...
- redis客户端、分布式锁及数据一致性
Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...
- Redis系列(二)--分布式锁、分布式ID简单实现及思路
分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...
- 在redis上实现分布式锁
/** *在redis上实现分布式锁 */ class RedisLock { private $redisString; private $lockedNames = []; public func ...
- 如何用redis正确实现分布式锁?
先把结论抛出来:redis无法正确实现分布式锁!即使是redis单节点也不行!redis的所谓分布式锁无法用在对锁要求严格的场景下,比如:同一个时间点只能有一个客户端获取锁. 首先来看下单节点下一般r ...
- redis系列:分布式锁
redis系列:分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- 一般实现分布式锁都有哪些方式?使用redis如何设计分布式锁?使用zk来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高?
#(1)redis分布式锁 官方叫做RedLock算法,是redis官方支持的分布式锁算法. 这个分布式锁有3个重要的考量点,互斥(只能有一个客户端获取锁),不能死锁,容错(大部分redis节点创建了 ...
随机推荐
- BadBoy+JMeter来录制和运行Web测试脚本
参考: http://jingyan.baidu.com/article/5d368d1ef548d43f61c05761.html http://www.51testing.com/html/00/ ...
- 牛客2018多校第五场E-room 最小费用最大流
题意:有n个寝室,每个寝室4个人,现在在搞搬寝室的活动,告诉你每个寝室之前的人员名单,和之后的人员名单,问最少需要几个人要搬寝室. 思路: 转化为最小费用最大流解决的二分图问题,对每个去年的宿舍,向每 ...
- C#开发BIMFACE系列22 服务端API之获取模型数据7:获取多个模型的楼层信息
系列目录 [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列21 服务端API之获取模型数据6:获取单模型的楼层信息>中介绍获取单个模型的所有楼层信息.某些场景下 ...
- Linux入门基础之 中
五.Linux 下获取帮助 没必要记住所有东西 Linux 提供了极为详细的帮助工具及文档,一定要养成查帮助文档的习惯,可以大大减少需要记忆的东西并且提高效率 5.1.HELP 几乎所有命令都可以使用 ...
- Nginx实现高可用(了解)
使用nginx实现反向代理和负载均衡时,nginx就是整个网站的入口了,所以需要保证nginx的高可用 主要资料包:链接:https://pan.baidu.com/s/1z_-xEM3uUICtZi ...
- jquery ajax到servlet出现中文乱码(utf-8编码下)
个人遇到的该问题有两大类: 第一类很普遍,就是jsp页面编码没有规定,servlet中接收参数没有转码,response没有使用setContentType()和setCharacterEncodin ...
- request对象的方法
request对象封装的是请求的数据,由服务器创建,作为实参传递给Servlet的方法,一个请求对应一个request对象,request对象可以获得请求数据. 1.获取请求行信息 (1)get提交 ...
- IO流——File类(文件流类)
java语言的输入输出操作是借助于输入输出包java.io来实现的,按传输方向分为输入流与输出流,从外设传递到应用程序的流为输入流,将数据从应用程序输入到外设的流为输出流. File类的构造方法: 1 ...
- Elastic Stack 笔记(四)Elasticsearch5.6 索引及文档管理
博客地址:http://www.moonxy.com 一.前言 在 Elasticsearch 中,对文档进行索引等操作时,既可以通过 RESTful 接口进行操作,也可以通过 Java 也可以通过 ...
- 采用WPF技术,开发OFD电子文档阅读器
前言 OFD是国家标准版式文档格式,于2016年生效.OFD文档国家标准参见<电子文件存储与交换格式版式文档>.既然是国家标准,OFD随后肯定会首先在政务系统使用,并逐步推向社会各个方面. ...