分布式锁tair redis zookeeper,安全性
tair分布式锁实现:https://yq.aliyun.com/articles/58928
redis分布式锁:https://www.cnblogs.com/jianwei-dai/p/6137896.html
https://blog.csdn.net/abbc7758521/article/details/77990048
redis、zookeeper分布式锁安全性讨论:https://blog.csdn.net/jackcaptain1015/article/details/71157004
http://mp.weixin.qq.com/s/JTsJCDuasgIJ0j95K8Ay8w http://mp.weixin.qq.com/s/4CUe7OpM6y1kQRK8TOC_qQ
使用setnx get getset实现分布式锁
多个进程执行以下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 操作会导致把其他进程已获得的锁释放掉,所以不需要再对锁进行处理。
public static boolean acquireLock(String lock) {
// 1. 通过SETNX试图获取一个lock
boolean success = false;
Jedis jedis = pool.getResource();
long value = System.currentTimeMillis() + expired + 1;
System.out.println(value);
long acquired = jedis.setnx(lock, String.valueOf(value));
//SETNX成功,则成功获取一个锁
if (acquired == 1)
success = true;
//SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时
else {
long oldValue = Long.valueOf(jedis.get(lock));
//超时
if (oldValue < System.currentTimeMillis()) {
String getValue = jedis.getSet(lock, String.valueOf(value));
// 获取锁成功
if (Long.valueOf(getValue) == oldValue)
success = true;
// 已被其他进程捷足先登了
else
success = false;
}
//未超时,则直接返回失败
else
success = false;
}
pool.returnResource(jedis);
return success;
}
分布式锁tair redis zookeeper,安全性的更多相关文章
- 分布式锁用Redis还是ZooKeeper?(转载)
文章系网络转载,侵删. 来源:https://zhuanlan.zhihu.com/p/73807097 为什么用分布式锁?在讨论这个问题之前,我们先来看一个业务场景. 图片来自 Pexels 为什么 ...
- 分布式锁用Redis与Zookeeper的使用
为什么用分布式锁? 在讨论这个问题之前,我们先来看一个业务场景: 系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会 ...
- 从分布式锁来看redis和zookpeer!
从分布式锁来看redis和zookpeer! 目前网上大部分的基于zookpeer,和redis的分布式锁的文章都不够全面.要么就是特意避开集群的情况,要么就是考虑不全,读者看着还是一脸迷茫.坦白说, ...
- 分布式锁----浅析redis实现
引言大概两个月前小伙伴问我有没有基于redis实现过分布式锁,之前看redis的时候知道有一个RedLock算法可以实现分布式锁,我接触的分布式项目要么是github上开源学习的,要么是小伙伴们公司项 ...
- 解析分布式锁之Redis实现(二)
摘要:在前文中提及了实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,本文主要阐述基于Redis的分布式锁,分布式架构设计如今在企业中被大量的应用,而在不同的分布 ...
- 分布式锁(redis/mysql)
单台机器所能承载的量是有限的,用户的量级上万,基本上服务都会做分布式集群部署.很多时候,会遇到对同一资源的方法.这时候就需要锁,如果是单机版的,可以利用java等语言自带的并发同步处理.如果是多台机器 ...
- SpringBoot集成Redis分布式锁以及Redis缓存
https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...
- Java分布式:分布式锁之Redis实现
Java分布式:分布式锁之Redis实现 分布式锁系列教程重点分享锁实现原理 Redis锁原理 核心命令 Redis分布式锁的原理是基于其SETNX命令,我们来看SETNX的解释. 实现过程 使用SE ...
- 【分布式锁】Redis实现可重入的分布式锁
一.前言 之前写的一篇文章<细说分布式锁>介绍了分布式锁的三种实现方式,但是Redis实现分布式锁关于Lua脚本实现.自定义分布式锁注解以及需要注意的问题都没描述.本文就是详细说明如何利用 ...
随机推荐
- EntityFramework 6 开篇
本系列文章主要来讲解理解以及怎样使用EntityFramework,写这个系列主要是因为部门里面准备来使用EF,为了让大家一起来学习,我每天发布1-2篇文章让大家一块参与学习.之前一直写在有道云笔记里 ...
- python requests的使用说明
#GET参数实例 requests.get('http://www.dict.baidu.com/s', params={'wd': 'python'}) #或 url = 'http://www.b ...
- 设置HTML5的video播放速度
var speed = 1.5;//设置速度 var vdo = document.getElementById("视频的id");//获取id vdo.playbackRate ...
- Mac OS下开启自带的apache服务
Apache路径 /etc/apache2/ [root@GGs-MacBook-Pro:/Volumes/SSD/blog#cd /etc/apache2/ [root@GGs-MacBook-Pr ...
- 【分库分表】sharding-jdbc—分片策略
一.分片策略 Sharding-JDBC认为对于分片策略存有两种维度: 数据源分片策略(DatabaseShardingStrategy):数据被分配的目标数据源 表分片策略(TableShardin ...
- MVC的局部视图传参的小技巧--见人才网头部导航
当我们设计一个局部视图时,当出现有类似导航的功能(如:选择左边的某个按钮跳到某个页,且顶部导航也作相印改变),如果我们选择把导航作为局部视图来处理,调用就可以做如下处理: @Html.RenderAc ...
- Clonal hematopoiesis of indeterminate potential(意义不明的克隆性造血)-CHIP
意义不明的克隆性造血是指由一个造血干细胞或者其他早期的起始血细胞为了更好的适应环境而发展成一个带有一些基因变异的亚型. 这个亚型带有基因变异一般是非驱动性的,而且该亚型占血细胞的比率跟年龄有很大的相关 ...
- 从HighGUI的一段代码中看OpenCV打开视频的方式
OpenCV的HighGUI提供了视频和摄像头的直接打开.那么它是如何实现的了?这里进行初步分析. ; switch(apiPreference) { default: ...
- 临时变量不能作为非const引用
转自:http://blog.csdn.net/u011068702/article/details/64443949 1.看代码 2.编译结果 3.分析和解决 就拿f(a + b)来说,a+b的值会 ...
- Ubuntu 16.04 + Nvidia 显卡驱动 + Cuda 8.0 (问题总结 + 解决方案)【转】
本文转载自:https://blog.csdn.net/Zafir_410/article/details/73188228 前言 前面好一阵子忙于写论文和改论文,好久没有做新实验了,最近又回到做实验 ...