分布式锁的Redis实现
当我们开始开发项目部署运行时,项目规模不大,只是在一个JVM实例中运行,对同一资源的并发访问用JDK自带的锁机制就可以解决资源同时访问的问题。而随着项目的不断发展,单体应用已经无法满足日益增长的访问需求,我们开始考虑多台部署,提高接收客户端的连接请求,提高项目的吞吐量。一台变多台,其中不可避免的问题就是如何控制解决不同线程对同一资源的并发访问。其中一种手段就是使用redis进行分布式锁的控制。
我们可以在获取访问资源锁之前判断redis中是否存在对应代表该资源锁key的value,如果存在,则说明已经被获取,反之还没有客户端获取该资源对应的锁,可以进行获取锁。
boolean lock = false;
try {
lcok = getLock(taskId); //获取锁
if (lock) {
doSomething(); //业务逻辑
}
} finally {
if (lock) {
releaseLock(taskId); //释放锁
}
}
public static boolean getLock(String taskId) {
if (existsKey(taskId)) {
return false;
} else {
setKey(taskId);
return true;
}
}
上面的部分实现代码给了一个大概的解决思路,看起来没有问题的,但是仔细看看还是存在问题滴,存在什么问题呢?
当正在执行doSomething()方法时,突然系统宕机挂掉了,无法执行释放锁的操作,redis中对应的资源key的锁一直存在,之后运行代码就会出现问题。另一个问题就是执行getLock(taskId)方法时,该方法不是原子性的,有可能同时两个线程都判断为不存在该资源锁,都执行了setKey方法,导致同时获得锁资源的情况。
如何解决上面的两个问题呢?从Redis官方API中有SET my_key my_value NX PX milliseconds的方法,得到了解决方案。它提供了一个只有在某个key不存在的情况下才会设置key的值的原子命令,该命令也能设置key值过期时间。其中,NX表示只有当键key不存在的时候才会设置key的值,PX表示设置键key的过期时间,单位是毫秒。
到现在是否完全解决了并发获取锁的问题了呢?系统可能存在这种情况,当客户端A获取锁之后,执行业务代码的时间超过了之前设置的过期时间,导致锁的自动释放,而客户端B刚好获得新的资源锁,但客户端A恰好执行完业务操作,释放锁的时候,该锁是客户端B重新获得的锁,导致出现问题。这时,我们想到可以在设置key值时给定一个随机数,在释放资源锁的同时,判断是否和之前设置的value值相同,相同则释放,反之不释放。
if(getKey(taskId)==random_value){
deleteKey(taskId);
}
很可惜,上面的整个if操作也不是原子性的,getKey方法和deleteKey方法之间由于某种原因而延迟1秒钟操作了,而这1秒内刚好设置的的超时时间而锁释放,被新的客户端获得锁,1秒之后执行deleteKey方法又会误删除新客户端的锁,问题依旧存在。接下来我们只要想办法解决上面判断的原子性就能解决误删除锁的问题。Redis可以使用Lua脚本保证操作的原子性。
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
其中ARGV[1]表示设置key时指定的随机值。由于Lua脚本的原子性,在Redis执行该脚本的过程中,其他客户端的命令都需要等待该Lua脚本执行完才能执行,所以不会出现上面所说的误删除锁问题。至此,使用Redis实现分布式锁的方案就相对完善了。上述分布式锁的实现方案中,都是针对单节点Redis而言的。
分布式锁的Redis实现的更多相关文章
- SpringBoot集成Redis分布式锁以及Redis缓存
https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...
- 解析分布式锁之Redis实现(二)
摘要:在前文中提及了实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,本文主要阐述基于Redis的分布式锁,分布式架构设计如今在企业中被大量的应用,而在不同的分布 ...
- 分布式锁tair redis zookeeper,安全性
tair分布式锁实现:https://yq.aliyun.com/articles/58928 redis分布式锁:https://www.cnblogs.com/jianwei-dai/p/6137 ...
- 从分布式锁来看redis和zookpeer!
从分布式锁来看redis和zookpeer! 目前网上大部分的基于zookpeer,和redis的分布式锁的文章都不够全面.要么就是特意避开集群的情况,要么就是考虑不全,读者看着还是一脸迷茫.坦白说, ...
- Java分布式:分布式锁之Redis实现
Java分布式:分布式锁之Redis实现 分布式锁系列教程重点分享锁实现原理 Redis锁原理 核心命令 Redis分布式锁的原理是基于其SETNX命令,我们来看SETNX的解释. 实现过程 使用SE ...
- [Java复习] 分布式锁 Zookeeper Redis
一般实现分布式锁都有哪些方式? 使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗? 这两种分布式锁的实现方式哪种效率比较高? 1. Zookeeper 都有哪些使用场 ...
- 分布式锁用Redis还是ZooKeeper?(转载)
文章系网络转载,侵删. 来源:https://zhuanlan.zhihu.com/p/73807097 为什么用分布式锁?在讨论这个问题之前,我们先来看一个业务场景. 图片来自 Pexels 为什么 ...
- 分布式锁(redis/mysql)
单台机器所能承载的量是有限的,用户的量级上万,基本上服务都会做分布式集群部署.很多时候,会遇到对同一资源的方法.这时候就需要锁,如果是单机版的,可以利用java等语言自带的并发同步处理.如果是多台机器 ...
- 【分布式锁】Redis实现可重入的分布式锁
一.前言 之前写的一篇文章<细说分布式锁>介绍了分布式锁的三种实现方式,但是Redis实现分布式锁关于Lua脚本实现.自定义分布式锁注解以及需要注意的问题都没描述.本文就是详细说明如何利用 ...
- 分布式锁用Redis与Zookeeper的使用
为什么用分布式锁? 在讨论这个问题之前,我们先来看一个业务场景: 系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会 ...
随机推荐
- 使用PyCharm创建Django项目及基本配置
https://segmentfault.com/a/1190000011576316 pycharm是个很不错的python开发工具,大大缩短了python项目的创建时间以及调试时间在使用pytho ...
- MYSQL查询查找重复的电子邮箱
编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱. 示例: +----+---------+| Id | Email |+----+---------+| 1 | a@b.com | ...
- mysql 存储过程学习
存储过程框架 DEMILITER $$ -- 重定义符 DROP PROCEDURE IF EXISTS store_procedure$$ -- 如果存在此名的存储过程,先删除 CREATE PRO ...
- 【JZOJ6271】锻造 (forging)
description analysis 首先看一下\(p=1\),即\(1\)以后的合成一定成功的情况 如果按照求期望值的一般做法求两把\(0\)合成\(1\)的期望,会画出一棵无穷大的树 这个的期 ...
- pom parent 标签
<!--parent用于引用父工程 1.统一管理jar包的版本,其依赖需要在子工程中定义才有效(比如此例) 2.统一的依赖管理(父工程的<dependencies>,子工程不必重新引 ...
- 如何检测 Web 服务请求丢失问题
导读 『StabilityGuide』是阿里多位阿里技术工程师共同发起的稳定性领域的知识库开源项目,涵盖性能压测.故障演练.JVM.应用容器.服务框架.流量调度.监控.诊断等多个技术领域,以更结构化的 ...
- System.Web.HttpContext.cs
ylbtech-System.Web.HttpContext.cs 1.程序集 System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken ...
- poj-3468-A Simple Problem with Integers-线段树入门+区间更新
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of op ...
- AI入门---从破解AI开始
我这里说的AI,并不是人工智能(Artificial Intelligence),只是Adobe illustrator.旁边有做设计的朋友,在他的指引下,对这个工具还颇感兴趣.就先下载个工具,闲暇时 ...
- docker registry (私有仓库)
首先要导入registry的镜像文件 1.普通的registry 一条命令创建一个仓库 docker run -d -p 5000:5000 --restart=always --name regis ...