Redis中是如何实现分布式锁的?

news2024/12/25 23:38:05

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

  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. 只要别人建立了一把分布式锁,你就得不断轮询去尝试获取锁。

alt

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();
}

加锁流程图

alt

解锁流程图

alt

我们可以看到,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/

顶尖架构师栈

关注回复关键字

【C01】超10G后端学习面试资源

【IDEA】最新IDEA激活工具和码及教程

【JetBrains软件名】 最新软件激活工具和码及教程

工具&码&教程

转载于:https://mp.weixin.qq.com/s/ELc_9k3QwEHdse_yFatDPw

本文由 mdnice 多平台发布

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

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

相关文章

JS基础语法

JS是一门面向对象的编程语言,运行在客户端的脚本语言,可以基于Node.js进行服务器端编程 JS的作用: 表单动态校验网页特效服务端开发 浏览器执行JS: 浏览器分为两部分:渲染引擎和JS引擎 渲染引擎用来解析HTML和CSS,…

2023中国智能产业高峰论坛丨文档图像大模型的思考与探索

# 前言 随着人工智能技术的不断发展,尤其是深度学习技术的广泛应用,多模态数据处理和大模型训练已成为当下研究的热点之一,这些技术也为文档图像智能处理和分析领域带来了新的发展机遇。 近期,2023第十二届中国智能产业高峰论坛…

打印由数字组成的金字塔图案——python

1222 33333 4444444 555555555打印由数字组成的金字塔图案。但n9时&#xff0c;如下图所示。 输入格式: 输入一个整数n&#xff08;1<A<9&#xff09;。 输出格式: 输出由数字组成的金字塔图案。 输入样例: 在这里给出一组输入。例如&#xff1a; 5输出样例: 在这…

软件设计模式系列之十二——外观模式

在软件设计中&#xff0c;经常会遇到需要与复杂子系统进行交互的情况。为了简化客户端与子系统之间的交互&#xff0c;提高系统的可维护性和可用性&#xff0c;外观模式应运而生。外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它提供一个统…

.NET超简单轻量级的HTTP请求组件Flurl

简介 Flurl是一个用于构建基于HTTP请求的C#代码的库。它的主要目的是简化和优雅地处理网络请求&#xff08;只用很少的代码完成请求&#xff09;。Flurl提供了一种简单的方法来构建GET、POST、PUT等类型的请求&#xff0c;以及处理响应和异常。它还提供了一些高级功能&#xf…

nndeploy:一款最新上线的支持多平台、简单易用、高性能的机器学习部署框架

项目地址&#xff1a;https://github.com/Alwaysssssss/nndeploy 介绍 nndeploy 是一款最新上线的支持多平台、高性能、简单易用的机器学习部署框架。做到一个框架就可完成多端(云、边、端)模型的高性能部署。 作为一个多平台模型部署工具&#xff0c;我们的框架最大的宗旨就…

Mac 上安装yt-dlp 和下载视频的操作

安装 打开终端&#xff0c;在终端输入 cd python的路径&#xff0c;然后输入pip3 install yt-dlp&#xff0c;如下图&#xff1b; 出现 如Successfully installed yt-dlp-2023.7.6 的时候&#xff0c;说明下载成功 下载 下载命令&#xff1a; yt-dlp --list-formats https…

来自华为的暴击?传高通裁员赔偿N+7 | 百能云芯

自9月20日起&#xff0c;高通裁员的新闻在网络上持续发酵。尽管市场充满了关于裁员细节的传言&#xff0c;但截至目前&#xff0c;高通官方尚未对此发表评论。 消息称&#xff0c;高通此次裁员的“重灾区”在上海的无线研发部门&#xff0c;甚至有传言称将直接关闭上海研发中心…

干货 | 汽车行业研发效能提升的挑战与实践案例

在 9 月 15 日的第七届 CSN 大会上&#xff0c;思码逸研发效能专家王艳萍受邀分享了《汽车行业研发效能提升的挑战与实践案例》。演讲包含了思码逸对多家汽车企业服务过程中总结出的行业痛点、解决方案&#xff0c;以及实践案例。 以下为演讲实录&#xff1a; 思码逸与很多知名…

基于微信小程序的校园生活管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言运行环境学生微信端的主要功能有&#xff1a;管理员的主要功能有&#xff1a;具体实现截图视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝1…

Aztec交易架构解析

1. 引言 前序博客有&#xff1a; Aztec的隐私抽象&#xff1a;在尊重EVM合约开发习惯的情况下实现智能合约隐私完全保密的以太坊交易&#xff1a;Aztec网络的隐私架构Aztec.nr&#xff1a;Aztec的隐私智能合约框架——用Noir扩展智能合约功能Account Abstraction账号抽象——…

【@胡锡进】大模型量化分析- 药明康德 603259.SH

我将使用不同的预测方法进行药明康德股票未来3天价格的预测。以下是每种方法的预测方法、详细代码和预测价格&#xff08;根据提供的数据进行模拟&#xff09;。 SARIMA模型预测&#xff1a; SARIMA&#xff08;季节性自回归移动平均&#xff09;模型适用于具有明显季节性的时…

PHP8中调换数组中的键值和元素值-PHP8知识详解

在php8中使用array_flip()函数可以调换数组中的键值和元素值。 在PHP8中使用array_flip()函数可以调换数组中的键值和元素值&#xff0c;示范代码如下&#xff1a; <?php$stu array("子涵"> 001,"欣怡"> 002,"梓涵">003,"晨曦…

华为OD机试 - 特异性双端队列(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、Java算法源码五、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 刷的越多…

TikTok的全球影响:跨文化、跨国界的短视频文化

随着TikTok的崛起&#xff0c;短视频文化正在以前所未有的方式迅速传播&#xff0c;跨足了不同国家和文化的边界。本文将探讨TikTok的全球影响&#xff0c;以及它如何促进了跨文化交流和文化融合。 短视频&#xff1a;跨越语言和文化的沟通工具 TikTok的短视频格式具有独特的跨…

Downie 4下载画质的设置方法,downie 4设置下载清晰度

downie4除了能够下载网页视频外&#xff0c;大家还能根据需要自定义下载文件的分辨率&#xff0c;是Mac电脑必备的下载工具&#xff0c;Downie4下载画质如何设置&#xff1f;下面就来告诉大家具体的设置方法吧。 下载&#xff1a;Downie 4中文直装版 没修改之前&#xff0c;Dow…

SpringBoot 之配置加密

Jasypt库的使用 Jasypt是一个Java简易加密库&#xff0c;用于加密配置文件中的敏感信息&#xff0c;如数据库密码。 Jasypt库与springboot集成&#xff0c;在实际开发中非常方便。 1、引入依赖 <dependency><groupId>com.github.ulisesbocchio</groupId>&…

人工智能AI 全栈体系(四)

第一章 神经网络是如何实现的 除了全连接神经网络外&#xff0c;还有其他形式的神经网络。 此节将讲述神经网络的另一种形式&#xff1a;卷积神经网络。 四、卷积神经网络 首先我们看看全连接神经网络有什么不足。正如其名字一样&#xff0c;全连接神经网络&#xff0c;两个…

STM32F4X UCOSIII 事件集

STM32F4X UCOSIII 事件集 事件的应用场景UCOSIII事件工作机制UCOSIII事件操作函数事件创建函数事件删除函数事件发送函数事件接收函数 UCOSIII事件例程 事件在RTOS中也是一种任务间同步的机制&#xff0c;事件不能传递数据。跟信号量不同的是&#xff0c;事件可以实现一对多&am…

C++11之基础篇

C11 C11简介统一的列表初始化&#xff5b;&#xff5d;初始化std::initializer_list 声明autodecltypenullptr范围for循环 STL中一些变化arrayforward_listunderored_map&#xff0c;underored_set C11简介 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;…