Java分布式锁面试题

1.为什么需要分布式锁?

public synchronized void test() {
    System.out.println("获取到锁");
}
public void test2() {
     synchronized (Test.class) {
          System.out.println("获取到锁");
     }
}

假设我们把上述代码部署到多台服务器上,这个互斥锁还能生效吗?答案是否定的,这时分布式锁应运而生。

2.Redis分布式锁?

接下来我给大家讲解完整的演变过程,让大家更深刻的理解分布式锁。

Redis setnx

线程1申请加锁,这时没有人持有锁,加锁成功:

127.0.0.1:6379> setnx lock 1
(integer) 1

线程2申请加锁,此时发现有人持有锁未释放,加锁失败:

127.0.0.1:6379> setnx lock 1
(integer) 0

线程1执行完成业务逻辑后,执行DEL命令释放锁:

127.0.0.1:6379> del lock
(integer) 1

存在问题:

①假设线程1执行到一半,系统挂了,这时锁还没释放,就会造成死锁。

②如果Redis加锁后,Master还没同步给Slave就挂了,会导致有两个客户端获取到锁

解决方案:setnx expire

Redis setnx expire

为了解决上述死锁问题,我们在setnx后,给这个key加上失效时间。

此时线程1加锁的代码改成:

127.0.0.1:6379> setnx lock 1 ## 加锁
(integer) 1
127.0.0.1:6379> expire lock 3 ## 设置 key 3秒失效
(integer) 1

存在问题:

①假设setnx lock 1执行成功了,但是expire lock 3执行失败了,还是会存在死锁问题,这两个命令需要保证原子性。

②失效时间是我们写死的,不能自动续约,如果业务执行时间超过失效时间,会出现线程1还在执行,线程2就加锁成功了,并有没达到互斥效果。

③如果Redis加锁后,Master还没同步给Slave就挂了,会导致有两个客户端获取到锁

解决方案:RedissonLock

RedissonLock

上述两个问题,RedissonLock都解决了,我通过源码给大家剖析,看RedissonLock是如何解决的,基础好的小伙伴可以好好读读源码,其实RedissonLock源码也不难。

我先写结论,基础较弱的小伙伴,只要记得结论就行:

①RedisssonLock底层使用的是lua脚本执行的redis指令,lua脚本可以保证加锁和失效指令的原子性。

②RedisssonLock底层有个看门狗机制,加锁成功后,会开启一个定时调度任务,每隔10秒去检查锁是否释放,如果没有释放,把失效时间刷新成30秒。这样锁就可以一直续期,不会释放。

我看的是3.12.5版本源码,不同版本实现上可能存在一些差异。

应用程序加锁代码:

RLock lock = redissonLock.getLock("anyLock");
lock.lock();

RedissonLock加锁核心代码:

RedissonLock获取锁核心代码:

底层加锁逻辑:

KEYS[1] = anyLock,锁的名称。

ARGV[1] = 30000,失效时间,通过lockWatchdogTimeout配置。

ARGV[2] = c1b51ddb-1505-436c-a308-b3b75b4bd407:1,他是ConnectionManager的ID,我们可以简单的把它理解为一个客户端的一个线程对应的唯一标志性。

RedissonLock解锁核心代码:

存在问题:如果redis是单节点,存在单节点故障问题;如果做主从架构,Redis加锁后,Master还没同步给Slave就挂了,会导致有两个客户端获取到锁

有小伙伴问我,如果这里我用集群会存在这个问题吗?集群的本质是分片,这个key最终还是会落到某个具体的节点,这个节点要么是单独存在,要么是主从架构,所以还是会存在上述问题。

解决方案:RedLock

补充:虽然RedLock可以解决上述问题,但是在生产环境中我们很少使用,因为它部署成本很高,相比RedissonLock性能也略微有所下降​。

如果业务能接受极端情况下存在互斥失败问题,并且对性能要求比较高,我们会选择RedissonLock,并做好响应​的兜底方案。

如果业务对数据要求绝对正确,​我们会采用Zookeeper来做分布式锁。​

Redlock

我们假设有5个完全相互独立的Redis Master单机节点,所以我们需要在5台机器上面运行这些实例,如下图所示(请注意这张图中5个Master节点完全相互独立)

为了取到锁,客户端应该执行以下操作:

①获取当前Unix时间,以毫秒为单位。

②依次尝试从N个Master实例使用相同的key和随机值获取锁(假设这个key是LOCK_KEY)。当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。

③客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。

④如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。

⑤如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。

缺点:像我们系统,并发量比较大,生产环境必须要做分片才能扛住并发,像上述方案,我们需要准备5个Redis集群,这种机器成本是非常高的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BPI-R3开发板 - atf编译

一. 获取源码 https://github.com/mtk-openwrt/arm-trusted-firmware 二. 编译步骤 和编译uboot一样,编译环境为ubuntu 18.04。交叉编译工具链我用的是openwrt编译生成的工具链,并设置到环境变量,如下: export PATH$PATH:/root/mt…

【大屏设计方案】

大屏设计方案一、非等比放大(填充满整个屏幕)目的屏幕比例大小和设计稿的差的不多目的屏幕比例大小和设计稿的差很多二、等比放大(比如16:9)解决方案之后就可以用rem了,有两种便利的方式:也可以用media 根据不同的屏幕…

膳食真菌在癌症免疫治疗中的作用: 从肠道微生物群的角度

谷禾健康 癌症是一种恶性肿瘤,它可以发生在人体的任何部位,包括肺、乳房、结肠、胃、肝、宫颈等。根据世界卫生组织的数据,全球每年有超过1800万人被诊断出患有癌症,其中约有1000万人死于癌症。癌症已成为全球范围内的主要健康问题…

@LoadBalanced注解原理

1.概述 使用注解就像是在代码中加入了一段魔法,让我们轻而易举的就实现了至关重要的功能。 就像LoadBalanced一样,将该注解使用在RestTemplate的Bean上,就可以实现负载均衡,就像下面这段代码: Configuration public…

新手UI设计师必读:火爆海外设计圈的设计资源!

Hello,各位好! 作为一名新手UI设计师,你是否无法完全搞清楚某些UI设计的基本原则和概念?你是否为使用哪款设计软件来开启你的设计之路而困扰?你是否想要在线学习设计排版、色彩搭配、形状和线条设计? 今天这…

rabbitMQ的详细介绍

1.概述 RabbitMQ是一个消息中间件:它接受并转发消息。你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按照这种逻辑RabbitMQ是一个快递站,一个快递员…

实验记录项目

1. 关于语谱图的通道的均值与方差 2023年 03月 27日 星期一 10:10:22 CST 使用tqwt 对每一份音频进行分解: 每份音频得到三个分量, cA分量: 近似分量,用于表征低频部分; cD分量: 高频分量,  res 剩余分量: 1.1 问题: 对每个分量使用如下变换,  使用Mel,  Shar…

SQL面试必会50题

引用: 视频讲解:https://www.bilibili.com/video/BV1q4411G7Lw/ SQL面试必会50题: https://zhuanlan.zhihu.com/p/43289968 图解SQL面试题:经典50题:https://zhuanlan.zhihu.com/p/38354000 其中重点为:1/2…

ChatGLM本地部署应用的实战方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

系统分析师每日练习错题知识点2

嵌入式系统---多核cpu 多核是多微处理器核的简称,是将两个或更多的独立处理器封装在一起,集成在一个电路中。多核处理器是单枚芯片(也称为硅核),能够直接插入单一的处理器插槽中,但操作系统会利用所有相关…

Java Web中的ServletContext对象

目录 ServletContext对象 获取上下文初始化参数的相关方法 创建ServletContext对象 1)通过 GenericServlet 提供的 getServletContext() 方法 2)通过 ServletConfig 提供的 getServletContext() 方法 3)通过 HttpSession 提供的 getServletCo…

Apache iotdb-web-workbench 认证绕过漏洞 CVE-2023-24829

漏洞简介影响版本 0.13.0 < 漏洞版本 < 0.13.3漏洞主要来自于 iotdb-web-workbench IoTDB-Workbench是IoTDB的可视化管理工具&#xff0c;可对IoTDB的数据进行增删改查、权限控制等&#xff0c;简化IoTDB的使用及学习成本。iotdb-web-workbench 中存在不正确的身份验证漏…

微服务架构(二)

Sentinel 使用及概念 什么是 Sentinel Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量 为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。Sentinel 具有以下特征: 丰富的应用场景&#xff1a;Sentin…

基于springboot实现医院信息管理系统【源码+论文】

基于springboot实现医院信管系统演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xf…

2023年全国DAMA-CDGP数据治理专家认证线上班招生简章

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

Vue3——v-md-editor(markDown编辑器)使用教程

Vue3——v-md-editor安装使用教程 安装 # 使用 npm npm i kangc/v-md-editor -SEditorMarkdown.vue页面用来封装此编辑器组件 Test.vue作为接受EditorMarkdown.vue的父组件&#xff0c;当测试页使用 路由部分要放入test.vue main.js部分全局引入组件 import EditorMarkdown f…

操作系统权限维持(十一)之Linux系统-SSH Wrapper后门

系列文章 操作系统权限维持&#xff08;一&#xff09;之Windows系统-粘贴键后门 操作系统权限维持&#xff08;二&#xff09;之Windows系统-克隆账号维持后门 操作系统权限维持&#xff08;三&#xff09;之Windows系统-启动项维持后门 操作系统权限维持&#xff08;四&…

算法强化每日一题--字符串中找出连续最长的数字串

hi,大家好,今天为大家带来一道题目 OR59 字符串中找出连续最长的数字串 描述 读入一个字符串str&#xff0c;输出字符串str中的连续最长的数字串 输入描述&#xff1a; 个测试输入包含1个测试用例&#xff0c;一个字符串str&#xff0c;长度不超过255。 输出描述&#xff1a; 在…

北邮22信通:(8)实验1 题目五:大整数加减法(搬运官方代码)

北邮22信通一枚~ 跟随课程进度每周更新数据结构与算法的代码和文章 持续关注作者 解锁更多邮苑信通专属代码~ 上一篇文章&#xff1a; 北邮22信通&#xff1a;&#xff08;7&#xff09;实验1 题目四&#xff1a;一元多项式&#xff08;节省内存版&#xff09;_青山如…

【人人都能读标准】17. 底层算法:ECMAScript的错误处理机制

本文为《人人都能读标准》—— ECMAScript篇的第17篇。我在这个仓库中系统地介绍了标准的阅读规则以及使用方式&#xff0c;并深入剖析了标准对JavaScript核心原理的描述。 我们在11.程序完整执行过程说过&#xff0c;一个程序的运行会经历三个阶段&#xff1a;初始化Realm环境…
最新文章