redis实现轮询算法_【07期】Redis中是如何实现分布式锁的?

点击上方“Java面试题精选”,关注公众号

面试刷图,查缺补漏

分布式锁常见的三种实现方式:

  1. 数据库乐观锁;

  2. 基于Redis的分布式锁;

  3. 基于ZooKeeper的分布式锁。

本地面试考点是,你对Redis使用熟悉吗?Redis中是如何实现分布式锁的。

要点

Redis要实现分布式锁,以下条件应该得到满足

互斥性

  • 在任意时刻,只有一个客户端能持有锁。

不能死锁

  • 客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

容错性

  • 只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。

实现

可以直接通过 set key value px milliseconds nx 命令实现加锁, 通过Lua脚本实现解锁。

//获取锁(unique_value可以是UUID等)
SET resource_name unique_value NX PX  30000

//释放锁(lua脚本中,一定要比较value,防止误解锁)
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

代码解释

  • set 命令要用 set key value px milliseconds nx,替代 setnx + expire 需要分两次执行命令的方式,保证了原子性,

  • value 要具有唯一性,可以使用UUID.randomUUID().toString()方法生成,用来标识这把锁是属于哪个请求加的,在解锁的时候就可以有依据;

  • 释放锁时要验证 value 值,防止误解锁;

  • 通过 Lua 脚本来避免 Check And Set 模型的并发问题,因为在释放锁的时候因为涉及到多个Redis操作 (利用了eval命令执行Lua脚本的原子性);

加锁代码分析

首先,set()加入了NX参数,可以保证如果已有key存在,则函数不会调用成功,也就是只有一个客户端能持有锁,满足互斥性。其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。最后,因为我们将value赋值为requestId,用来标识这把锁是属于哪个请求加的,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。

解锁代码分析

将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。在执行的时候,首先会获取锁对应的value值,检查是否与requestId相等,如果相等则解锁(删除key)。

存在的风险

如果存储锁对应key的那个节点挂了的话,就可能存在丢失锁的风险,导致出现多个客户端持有锁的情况,这样就不能实现资源的独享了。

  1. 客户端A从master获取到锁

  2. 在master将锁同步到slave之前,master宕掉了(Redis的主从同步通常是异步的)。主从切换,slave节点被晋级为master节点

  3. 客户端B取得了同一个资源被客户端A已经获取到的另外一个锁。导致存在同一时刻存不止一个线程获取到锁的情况。

redlock算法出现

这个场景是假设有一个 redis cluster,有 5 个 redis master 实例。然后执行如下步骤获取一把锁:

  1. 获取当前时间戳,单位是毫秒;

  2. 跟上面类似,轮流尝试在每个 master 节点上创建锁,过期时间较短,一般就几十毫秒;

  3. 尝试在大多数节点上建立一个锁,比如 5 个节点就要求是 3 个节点 n / 2 + 1;

  4. 客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了;

  5. 要是锁建立失败了,那么就依次之前建立过的锁删除;

  6. 只要别人建立了一把分布式锁,你就得不断轮询去尝试获取锁。

979569b1497e94f5606f3ef25176cca2.png

Redis 官方给出了以上两种基于 Redis 实现分布式锁的方法,详细说明可以查看:

https://redis.io/topics/distlock 。

Redisson实现

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还实现了可重入锁(Reentrant Lock)、公平锁(Fair Lock、联锁(MultiLock)、 红锁(RedLock)、 读写锁(ReadWriteLock)等,还提供了许多分布式服务。

Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

Redisson 分布式重入锁用法

Redisson 支持单点模式、主从模式、哨兵模式、集群模式,这里以单点模式为例:

// 1.构造redisson实现分布式锁必要的Config
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword("123456").setDatabase(0);
// 2.构造RedissonClient
RedissonClient redissonClient = Redisson.create(config);
// 3.获取锁对象实例(无法保证是按线程的顺序获取到)
RLock rLock = redissonClient.getLock(lockKey);
try {
    /**
     * 4.尝试获取锁
     * waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
     * leaseTime   锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
     */
    boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);
    if (res) {
        //成功获得锁,在这里处理业务
    }
} catch (Exception e) {
    throw new RuntimeException("aquire lock fail");
}finally{
    //无论如何, 最后都要解锁
    rLock.unlock();
}

加锁流程图

b2c6b2eef12c241b606879cfef8b2788.png

解锁流程图

bac64e51e77299461b70ca32d19bc1ee.png

我们可以看到,RedissonLock是可重入的,并且考虑了失败重试,可以设置锁的最大等待时间, 在实现上也做了一些优化,减少了无效的锁申请,提升了资源的利用率。

需要特别注意的是,RedissonLock 同样没有解决 节点挂掉的时候,存在丢失锁的风险的问题。而现实情况是有一些场景无法容忍的,所以 Redisson 提供了实现了redlock算法的 RedissonRedLock,RedissonRedLock 真正解决了单点失败的问题,代价是需要额外的为 RedissonRedLock 搭建Redis环境。

所以,如果业务场景可以容忍这种小概率的错误,则推荐使用 RedissonLock, 如果无法容忍,则推荐使用 RedissonRedLock。

参考

https://github.com/javazhiyin/advanced-java/
https://crazyfzw.github.io/2019/04/15/distributed-locks-with-redis/

最近三期

【04期】分库分表之后,id 主键如何处理?

【05期】消息队列中,如何保证消息的顺序性?

【06期】单例模式有几种写法?

精选常见面试题、技术知识点,帮助开发者查缺补漏。

6472c9541726077b811cef1fd6f83fb4.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/427859.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端radio单选框默认选中_开发记录篇前端内容1

有段时间没有更新文章了,因为是用的公司电脑,没有虚拟机,所以就没法演示hadoop相关的东西了,而且大数据篇的东西需要花费一些时间和精力去收集整理内容,那大数据篇就先暂停一下。最近这段时间的话我可能会更新一些开发…

专属海报小程序_剑3泡泡 | 小程序给你一份专属的账号海报!

01按照惯例,这里是简介paopaods.com本期推送的是:如何正确的使用小程序每个账号均可小程序【剑3泡泡】搜到,生成专属账号海报!点击底部【点我卖号】即可拥有!02教程开始之前,安利paopaods.com泡泡家定金调整…

td不允许自己扩展_V神原文详解:通过及时性检测器(TD)解决区块链的51%攻击问题...

注:原文作者是以太坊联合创始人Vitalik Buterin,在这篇文章中,他提出了一种称为及时性检测器(TD)的构造,以试图解决区块链51%攻击的问题。(图:Vitalik Buterin)以下为译文:摘要我提出了一种基于Lamport 99%…

Hadoop安装之JDK在Centos虚拟机中安装

安装jdk.bin和jdk.tar.gz打的办法 安装jdk.bin 安装好的VM Centos7的虚拟机, 1、查看是否是64位操作系统: cat /proc/cpuinfo | grep flags | grep lm | wc -l 如果结果>0 则是64位操作系统 2、JDK 中 jdk-6u41-linux-x64.bin 和 jdk-6u41-linux-x64…

Exp3 免杀原理与实践

---恢复内容开始--- 一,实验内容 利用多种工具实现实现恶意代码免杀在另一台电脑上,杀软开启的情况下,实现运行后门程序并回连成功二,实验步骤 (1)使用msf编码器生成的后门程序 这里可以直接用上次实验生成…

如何进入指定文件目录_Python如何遍历操作指定文件目录下的全部Excel文件?

Python Tablib是麻省理工学院授权的与格式无关的表格数据集库。支持导入、导出和操作表格数据集,轻松的将数据导出为各种不同的格式,包括excel,json,html,yaml,csv,tsv等格式。接下来&#xff0…

《雪吁》

凛冽隆冬风骨寒,层云避日雾无边; 渐絮残花萧萧夜,窗前瘦花犹遮帘。 转载于:https://www.cnblogs.com/morron/p/8749430.html

条形图坐标轴_解密咨询报告中常见的双层条形图的制作方法

为了增加PPT的设计灵感,我除了经常逛一些设计社区之外,也会收集的各个公司咨询报告来学习。昨天我看了4份数据报告,发现这4份数据报告中都出现了一个共同的图表类型。第1个图表自于IXDC发布的《2018年中国用户体验行业调查报告》,…

赋值给集合_ArrayList集合源码

ArrayList简介ArrayList 是 Java 集合框架中比较常用的数据结构了。ArrayList是可以动态增长和缩减的索引序列,内部封装了一个动态再分配的Object[]数组这里我们可以看到ArrayList继承抽象类AbstractList,实现了 List 接口,同时还实现了 Rand…

剪切文件_lammps模拟带缺陷镍板剪切变形(in文件及注释)

本期给大家带来lammps模拟带缺陷镍板剪切变形的in文件及其详细注释。初始模型如图一所示:图1 生成的初始模型 in文件及注释如下:#利用eam势函数模拟带缺陷镍板的剪切#模型构成——上下镍板夹可动镍块,镍块中有圆柱形缺陷,移动上镍…

为什么将表格的method改为post后就无法工作_用Python将Keras深度学习模型部署为Web应用程序...

构建一个很棒的机器学习项目是一回事,但归根结底,你希望其他人能够看到你的辛勤工作。当然,你可以将整个项目放在GitHub上,但是怎么让你的祖父母也看到呢?我们想要的是将深度学习模型部署为世界上任何人都可以访问的We…

centos 源码安装mysql5.6_CentOS 7下源码安装MySQL 5.6

目录准备工作运行环境确认你的安装版本下载MySQL安装MySQL准备安装环境编译和安装配置MySQL单实例配置单实例配置方法添加防火墙启动MySQL重启MySQL多实例配置什么是多实例多实例配置方法创建启动文件初始化数据库配置防火墙启动MySQL登陆MySQL重启MySQL准备工作运行环境本文的…

跳一跳

转载于:https://www.cnblogs.com/shanhua-fu/p/8807348.html

树莓派 无法安装mysql_树莓派安装mysql

前置,更新系统sudo apt-get updatesudo apt-get upgrade安装与配置MySQL直接安装mysql的话,默认下载的是MariaDB,两者差别不大,用法一样。如果真想下载mysql,需要换源,新版的Linux系统自带的是MariaDB&…

ABP框架使用 Swagger

在最近的一个项目中用到了 ABP框架 http://aspnetboilerplate.com/ ,第一次接触到 Swagger https://swagger.io/ 以及前后端的完全分离 在ABP官网下载下来的ABP框架结构【基于ASP.NET MVC5.x的】如图: ABP的EntityFramework 是Code First Mode的,所以在配…

JVM第五部分 高效并发

java 内存模型与线程 硬件内存模型 java内存模型 主内存vs工作内存 所有变量都在主内存(虚拟机内存的一部分),每条线程都有自己的工作内存,线程所有用到的变量都必须从主内存拷贝出来(不能直接读写主内存变量&#xff…

hadoop元数据mysql中表字段_hive mysql元数据表说明

2019独角兽企业重金招聘Python工程师标准>>>数据库相关的表DBS该表存储Hive中所有数据库的基本信息,字段如下:元数据表字段说明示例数据DB_ID数据库ID2DESC数据库描述测试库DB_LOCATION_URI数据库HDFS路径hdfs://namenode/user/hive/warehouse/…

CentOs7.2编译安装Nginx服务器

1. 安装nginx依赖 首先安装nginx的依赖 yum install gcc gcc-c openssl openssl-devel cyrus-sasl-md5 2,创建nginx用户 如果没有nginx,启动nginx时会报错 [rootlocalhost nginx-1.11.2]# /usr/local/nginx/sbin/nginx nginx: [emerg] getpwnam("ng…

2017-2018-2 20179215《网络攻防实践》第六周作业

2017-2018-2 20179215《网络攻防实践》 第六周学习总结 课本学习笔记 一、TCP/IP网络协议攻击 1.网络安全的属性:机密性 、完整性 、可用性 、真实性 、不可抵赖性 。 2.网络攻击的基本模式分为:截获(嗅探 与 监听) 、中断&#x…

mysql分布式一致性hash_分布式哈希一致性

问题分布式哈希一致性的动机是什么?相比其他有什么好处概述我们谈论的分布式哈希一致性常常使用在负载均衡,权衡一个策略的好坏,我们常常谈到扩展性和容错性。我们可以从以下两个方面来考量扩展性 :水平扩展和垂直扩展&#xff0c…