在使用分布式锁进行互斥资源访问时候,我们很多方案是采用redis的实现。
固然,redis的单节点锁在极端情况也是有问题的,假设你的业务允许偶尔的失效,使用单节点的redis锁方案就足够了,简单而且效率高。
redis锁失效的情况:

  1. 客户端1从master节点获取了锁
  2. master宕机了,存储锁的key还没来得及同步到slave节点上
  3. slave升级为master
  4. 客户端2从新的master上获取到同一个资源的锁

于是,客户端1和客户端2同事持有了同一个资源的锁,锁的安全性被打破。
如果我们不考虑这种极端情况,需要实现一个基于单节点redis锁的大致流程:

set cache_key random_seed NX PX 30000

上面这个set命令拆解开就是:

setnx cache_key random_seed
expire cache_key 30

虽然这两组命令执行的效果一样,但是第二个是非原子性操作,如果执行了setnx成功,但是expire失败的话,就会造成这个key一直存在了,无法释放的情况。
redis的作者也指出,在使用单节点redis锁的时候,设置一个随机种子作为key的值是很有必要的,保证了一个客户端释放的锁必须是自己所持有的那个锁。假设获取锁时set的不是一个随机数,而是一个固定值,那么可能会出现下面的情况:

  1. 客户端1获取锁成功
  2. 客户端1在某个操作上阻塞了很长时间
  3. 过期时间到了,锁自动释放(但是在客户端1看来自己还是持有锁中)
  4. 客户端2获取到了对应同一个资源的锁
  5. 客户端1从阻塞中恢复了,释放掉自己持有的锁,也就是释放掉了客户端2持有的锁

客户端2的锁被客户端1是否,失去安全性。
释放锁的操作,很多人直接用del命令,这会有很大的问题,保证不了这个key是被加锁人锁删。这时候需要用到随机数了。释放锁的操作有三步:

  1. get 所持有锁
  2. 判断这个锁是否自己所持有
  3. 删除持有锁

所以,这三步要保证原子性。用lua脚本来执行,redis官方已经提供脚本文件。

if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end

这段脚本在执行的时候,需要把前面的随机数作为argv[1] 的值传进去,把cache_key作为keys[1]的值传进去。

public class RedisLockHelper {@Resourceprivate R2mClusterClient r2mClusterClient;/*** 类似于setNx的功能,同时设置过期时间为expire毫秒** @param key    加锁key* @param value  确保在加锁时间内的唯一因子* @param expire 过期时间的毫秒数* @return*/private String setLock(String key, String value, long expire) {return this.set(key, value, "NX", "PX", expire);}/*** 删除指定key value* 如果 r2m中 key 对应的value==value   返回 1* 如果 r2m中 key 对应的value!=value   返回 0** @param key* @return*/private boolean atomDelete(String key, String value) {List<String> values = new ArrayList<>();values.add(value);String sb = "if redis.call('get',KEYS[1])==ARGV[1] then " +" return redis.call('del',KEYS[1]) " +" else " +" return 0" +" end";if (this.eval(sb, key, values) == 1) {return true;}return false;}private Long eval(String mobel, String key, List<String> value) {return (Long) this.r2mClusterClient.eval(mobel, key, value);}private String set(String key, String value, String nxxx, String expx, long time) {return this.r2mClusterClient.set(key, value, nxxx, expx, time);}
}

r2mClusterClient 就是jedis客户端的封装。

基于redis的分布式锁解析相关推荐

  1. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  2. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  3. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  4. redis系列:基于redis的分布式锁

    一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...

  5. 基于 Redis 的分布式锁到底安全吗?

    [完整版] 网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现 ...

  6. js 拉勾网效果_Node.js 中实践基于 Redis 的分布式锁实现

    在一些分布式环境下.多线程并发编程中,如果对同一资源进行读写操作,避免不了的一个就是资源竞争问题,通过引入分布式锁这一概念,可以解决数据一致性问题. 作者简介:五月君,Nodejs Developer ...

  7. php使用redis分布式锁,php基于redis的分布式锁实例详解

    在使用分布式锁进行互斥资源访问时候,我们很多方案是采用redis的实现. 固然,redis的单节点锁在极端情况也是有问题的,假设你的业务允许偶尔的失效,使用单节点的redis锁方案就足够了,简单而且效 ...

  8. 基于Redis的分布式锁到底安全吗(上)?

    网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现算法也看似合 ...

  9. 基于Redis的分布式锁实现

    本文转自 一.分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问,Java中我们一般可以使用synchronized语法和ReetrantLock去保证,这实际上是本地锁的 ...

最新文章

  1. [CQOI2012] 局部极小值(状压DP + 容斥 + 搜索)
  2. Unable to parse the date: 2017-12-30 日期格式转化失败
  3. ERP会给企业带来什么好处?
  4. Language binding(语言绑定)
  5. jQuery 1.3 API 参考文档中文版
  6. 新华三培训2---HSRP/VRRP/GLBP
  7. 在线问卷调查系统分析与实现
  8. 三阶段最小二乘法 回归分析 3SLS python实现
  9. 2022-2028年全球与中国婴儿食品包装行业产销需求与投资预测分析
  10. #爬取电影天堂的磁力链接#
  11. 深度学习基础理论(学习中持续更新)
  12. 如何确定当前的iPhone /设备型号?
  13. MAC地址 单播,组播,广播
  14. 利用线性布局和相对布局实现一个简单的页面
  15. electron-vue+electron-updater实现自动更新
  16. 后缀自动机(我太蒟了!)
  17. 度分秒与经纬度的互转
  18. 小样本few shot
  19. navicat数据库管理软件延长试用期
  20. 开源的晶体管测试仪版本注意事项

热门文章

  1. aac蓝牙编解码协议_蓝牙音频编码哪个音质好?今天我们来逐一解读
  2. html5新特性 移除哪些,html5\CSS3有哪些新特性、移除了哪些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分HTML和HTML5?...
  3. c语言运动会成绩统计报告,C语言程序设计运动会成绩统计系统1研究报告.doc
  4. python打包的exe如何免杀_通过Python实现Payload分离免杀过程详解
  5. java对象的状态,Java编程菜鸟课程:状态对象
  6. Vmware 和 Windows 代理设置
  7. mysql 函数的参数_MySQL中的数值函数
  8. 山东计算机编程哪个学校好,山东男孩,8岁懂电脑编程,10岁考上南科大,最后为何惨遭退学?...
  9. postgresql 编码_开源力量与职业发展 --写给对PostgreSQL有志趣的朋友们
  10. 【 MATLAB 】DFT的性质讨论(二)序列的循环移位及其 MATLAB 实现(频域方法)