当我们开始开发项目部署运行时,项目规模不大,只是在一个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实现的更多相关文章

  1. SpringBoot集成Redis分布式锁以及Redis缓存

    https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...

  2. 解析分布式锁之Redis实现(二)

    摘要:在前文中提及了实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,本文主要阐述基于Redis的分布式锁,分布式架构设计如今在企业中被大量的应用,而在不同的分布 ...

  3. 分布式锁tair redis zookeeper,安全性

    tair分布式锁实现:https://yq.aliyun.com/articles/58928 redis分布式锁:https://www.cnblogs.com/jianwei-dai/p/6137 ...

  4. 从分布式锁来看redis和zookpeer!

    从分布式锁来看redis和zookpeer! 目前网上大部分的基于zookpeer,和redis的分布式锁的文章都不够全面.要么就是特意避开集群的情况,要么就是考虑不全,读者看着还是一脸迷茫.坦白说, ...

  5. Java分布式:分布式锁之Redis实现

    Java分布式:分布式锁之Redis实现 分布式锁系列教程重点分享锁实现原理 Redis锁原理 核心命令 Redis分布式锁的原理是基于其SETNX命令,我们来看SETNX的解释. 实现过程 使用SE ...

  6. [Java复习] 分布式锁 Zookeeper Redis

    一般实现分布式锁都有哪些方式? 使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗? 这两种分布式锁的实现方式哪种效率比较高? 1. Zookeeper 都有哪些使用场 ...

  7. 分布式锁用Redis还是ZooKeeper?(转载)

    文章系网络转载,侵删. 来源:https://zhuanlan.zhihu.com/p/73807097 为什么用分布式锁?在讨论这个问题之前,我们先来看一个业务场景. 图片来自 Pexels 为什么 ...

  8. 分布式锁(redis/mysql)

    单台机器所能承载的量是有限的,用户的量级上万,基本上服务都会做分布式集群部署.很多时候,会遇到对同一资源的方法.这时候就需要锁,如果是单机版的,可以利用java等语言自带的并发同步处理.如果是多台机器 ...

  9. 【分布式锁】Redis实现可重入的分布式锁

    一.前言 之前写的一篇文章<细说分布式锁>介绍了分布式锁的三种实现方式,但是Redis实现分布式锁关于Lua脚本实现.自定义分布式锁注解以及需要注意的问题都没描述.本文就是详细说明如何利用 ...

  10. 分布式锁用Redis与Zookeeper的使用

    为什么用分布式锁?   在讨论这个问题之前,我们先来看一个业务场景: 系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会 ...

随机推荐

  1. linux 服务器安装mysql5.6

    1.移除CentOS默认的mysql-libs: whereis mysql 2.为了避免冲突,先移除CenttOS上默认的mysql-libs: yum remove mysql-libs 3.然后 ...

  2. [转]spring入门(六)【springMVC中各数据源配置】

    在使用spring进行javaWeb开发的过程中,需要和数据库进行数据交换,为此要经常获取数据库连接,使用JDBC的方式获取数据库连接,使用完毕之后再释放连接,这种过程对系统资源的消耗无疑是很大的,这 ...

  3. leetcood学习笔记-79-单词搜索

    题目描述: 方法一;回溯 class Solution: def exist(self, board: List[List[str]], word: str) -> bool: max_x,ma ...

  4. 解析Mybatis入门第二天

    入门第二天 目的:使用Mybatis对数据库中的数据进行简单的操作.例如:增.删.改.查. 前言:同样是使用idea创建一个普通的maven工程(如何创建一个普通的Maven工程可以参考入门第一天的详 ...

  5. 一阶段项目 总结 之 两张图片对比 手写 jquery 也可以使用beer slider 插件

    <!DOCTYPE html><html> <head>  <meta charset="utf-8">  <title> ...

  6. xkl的各种沙雕低错

    13,特判判掉20分算不算? 12,linux用c++11编译: g++ -std=c++11 -o a a.cpp g++ a.cpp -std=c++11 -o a //g++ a.cpp -st ...

  7. Java-Maven-pom.xml-project-repositories:repositories

    ylbtech-Java-Maven-pom.xml-project-repositories:repositories <!--发现依赖和扩展的远程仓库列表. --> 1. platfo ...

  8. day 68 Django基础四之模板系统

      Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关 ...

  9. PostMan授权认证使用

    Authorization 对于很多应用,出于安全考虑我们的接口并不希望对外公开.这个时候就需要使用授权(Authorization)机制. 授权过程验证您是否具有访问服务器所需数据的权限. 当发送请 ...

  10. 09_springmvc图片上传

    一.上传图片 1.需求 在修改商品页面,添加上传商品图片的功能 2.springmvc中对多部件类型解析 在页面form中提交enctype="multipart/form-data&quo ...