当前位置: 首页 > news >正文

【Redis】一种常见的Redis分布式锁原理简述

本文主要简述一下基于set命令的Redis分布式锁的原理。

一,a线程持有的锁不要被b线程同时持有→setnx

抢锁的时候,最核心的就是,a线程持有的锁不要被b线程同时持有,放在基于set命令的redis分布式锁中来看,就是“如果锁(key)存在我就不能抢,锁(key)不存在我才能抢”,

用原子的redis命令来说就是

setnx key value

key可以设置为你业务中要抢的锁的名字,和其他key区分开。

一开始,redis提供了set、setex(设置key value的同时设置过期时间)、setnx(如果不存在key就设置key value)。

二,如果锁被别人释放了怎么办→ThreadLocal和UUID

一个比较常见的担心是,如果a线程加的锁,被b线程释放了怎么办,毕竟只是一个set命令,用del就可以删除,也就是解锁,那怎么办呢。

在前面我们只设置了key的名字,对value没有做要求。其实我们可以给value加一个唯一ID,让别的线程识别到这个锁是否是自己持有。

线程id是否可以呢,我们直接用线程的id作为value,让线程看一下是否是自己的id,简单直接。答案是不可以,线程id在机器中是唯一的,但是这是分布式锁,多个机器之间,线程id不唯一。

我们倒也不用直接跳到分布式id这么远,其实uuid足矣。uuid中包括了机器的IEEE识别号(如果有网卡,从网卡的mac地址获得),优点是全球唯一且简单、代码方便,uuid不用于自增主键的原因是它不区域递增,以及可能造成网卡的mac地址泄露(曾用于寻找梅丽莎病毒制作者)。

此时我们就需要用到ThreadLocal,让每个线程私有uuid。就这样,我们加入了ThreadLocal和UUID,解决了锁被其他线程释放的问题。

三,锁无人释放问题→加过期时间

1,只靠setnx命令,死锁无法释放

那么紧接着问题来了, 如果加锁的线程挂掉了,导致锁无法正常释放怎么办?要知道,redis的数据如果没有特意设置过期时间,默认的是永不过期。所以我们要设置一个过期时间。

redis中设置过期时间的命令为expire命令,我们当然可以使用expire来给上面的setnx命令来加过期时间,如下:

setnx lock XXX
expire lock 10 //给lock键设置过期时间为10秒

2,setnx+expire命令不够原子

第二个问题来了,setnx+expire命令不够原子,即如果有线程只执行了加锁命令setnx,在第二个命令expire执行之前就挂掉了,又怎么办呢?因为这两个是分开执行的,意味着是存在这种可能的。因此我们就要想方法来将其一次执行。

(1),set key value ex second nx

正如一开始所述,redis在一开始只提供了set、setnx、setex几个命令,却没有其他参数,因此要执行必须分开执行。

在 Redis 2.6.12 之后,Redis 扩展了 SET 命令的参数,使我们可以直接在一条命令中完成所有操作,即如果不存在,再设置Key value(nx),同时设置过期时间(ex)。

注,set命令中,ex参数设置秒,px参数设置毫秒

(2),Lua脚本

redis整合了Lua语言,我们可以基于redis的eval命令,通过Lua脚本来完成原子性操作;

eval命令如下:

eval 脚本内容 Ke个数 key列表 参数列表

如果觉得每次都要上传Lua脚本占带宽,还可以在Redis启动时将Lua脚本上传,由redis将脚本缓存,客户端拿到sha1,在使用lua脚本时只需要上传sha1值即可[1]。即通过script load命令上传脚本,得到sha1,再基于evalsha命令,通过sha1参数执行指定的lua脚本。

evalsha命令使用示例如下:

script load "${cat lua_demo.lua}"
evalsha 脚本sha1值 key个数 key列表 参数列表

四,如何评定过期时间→看门狗线程续期

现在好了,一个基本的redis分布式锁的方案已经有了,那么还有什么问题呢。仔细想想就会发现,问题出在了业务执行时间上。我们应该如何衡量业务执行时间并由此设置过期时间呢?

一个项目里,有的业务执行时间长,有的执行时间短。就算是同一个业务,你通过链路追踪或者监控知道了业务执行大多数是多久,下面分为两种情况,

情况1,我们假设就按照大多数业务能完成的时间来设置过期时间,这肯定是不行的,因为有的业务没完成就释放了锁,极容易出现问题。

情况2,我们按照一个比较大,大到应该不可能出现问题的过期时间,总行了吧?也不行,第一,“应该不可能”,谁知道以后有没有可能有的业务就是时间长到超过了过期时间。第二,为了少数业务执行时间长的情况,而给所有业务,包括大多数只需要较短持有锁时间的业务,都施加很长的过期时间,很明显项目并发能力会严重下降。

怎么办呢,长了也不行,短了也不行。这时候,我们可以加入看门狗方案。什么意思呢,就是说我们可以给线程设置一个不算长对于大多数线程都比较合理的时间,哪怕短点也无所谓。我们专门设置一个守护线程(thread.setDaemon(true))用于监控线程的看门狗线程,看门狗线程会在过期时间快到了且锁还没有被释放时,就去用expire命令给锁续期。

同时配合一个延迟队列DelayQueue(本质是个堆Heap),在加锁时,将装有线程id和续期时间(注意是续期时间,续期时间要比key的过期时间早一点)的entity扔进去,延迟队列根据续期时间排序,这样堆中排在最上面的永远是续期时间最近的entity(堆的特性)。

看门狗线程的任务内容,就是while循环,对延迟队列用take方法阻塞的去拿最近一个需要判断是否要续期的entity,有的话就进行续期,这样我们就可以用一个线程完成对整个项目的所有锁的续期,这样的分布式锁,耗时短的业务用一次过期时间就可以完成,耗时长的业务也可以有看门狗线程来实现续期过期时间。

五,总结→建议不要自己开发,用现成的如Redisson

上面实现的分布式锁,解决了如下几个问题

  • a线程持有的锁不要被b线程同时持有→setnx
  • 如果锁被别人释放了怎么办→ThreadLocal和UUID
  • 只依靠setnx,持有锁的线程挂掉,导致无人去释放锁→给锁添加过期时间,expire命令设置过期时间
  • setnx和expire不够原子→set命令和参数ex、nx,或者lua脚本配置命令eval、evalsha
  • 过期时间不好评定→加入看门狗守护线程,配合延迟队列,看门狗线程用死循环,使用take方法阻塞的等待将最近要续期的任务,将其续期。

实际使用上,我个人的看法是轮子不需要重复开发,我们只需要用Redisson实现的分布式锁,就具有看门狗线程[2]。简简单单两三行代码,就有更完善的分布式锁使用。除非一些特殊的原因,不然不要重复造轮子,以及如非必要,勿增实体(奥卡姆剃刀原则)。

        RLock testLock = redissonClient.getLock("test_lock");boolean res = testLock.tryLock(10, TimeUnit.SECONDS);

参考文章:
[1],用jedis执行lua脚本
[2],redisson中的看门狗机制总结

相关文章:

【Redis】一种常见的Redis分布式锁原理简述

本文主要简述一下基于set命令的Redis分布式锁的原理。 一,a线程持有的锁不要被b线程同时持有→setnx 抢锁的时候,最核心的就是,a线程持有的锁不要被b线程同时持有,放在基于set命令的redis分布式锁中来看,就是“如果锁…...

HOT100_最大子数组和

class Solution {public int maxSubArray(int[] nums) {int[] dp new int[nums.length];int res nums[0];dp[0] nums[0];for(int i 1; i< nums.length; i){dp[i] Math.max(nums[i] ,dp[i-1] nums[i]);res Math.max(res, dp[i]);}return res;} }...

DiskGenius工具扩容Mac OS X Apple APFS分区

DiskGenius是一款功能强大的磁盘分区工具&#xff0c;它支持Windows和Mac OS X系统&#xff0c;可以用于管理硬盘分区&#xff0c;包括扩容Mac OS X的Apple APFS分区。然而&#xff0c;直接使用DiskGenius来扩容Mac OS X的APFS分区可能存在一定的风险&#xff0c;因为不是专门为…...

从零开始的LeetCode刷题日记:70. 爬楼梯

一.相关链接 题目链接&#xff1a;70. 爬楼梯 二.心得体会 这道题还是动规五部曲。 1.首先是dp数组及其下标的含义&#xff0c;dp记录了每层楼梯对应的爬的方法&#xff0c;每个下标存储每个对应楼层。 2.然后是递归公式&#xff0c;其实每一层楼都是可以从下面一层和下面…...

Unity照片墙效果

Unity照片墙效果&#xff0c;如下效果展示 。 工程源码...

【自动化利器】12个评估大语言模型(LLM)质量的自动化框架

LLM评估是指在人工智能系统中评估和改进语言和语言模型的过程。在人工智能领域&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;及相关领域&#xff0c;LLM评估具有至高无上的地位。通过评估语言生成和理解模型&#xff0c;LLM评估有助于细化人工智能驱动的语言相…...

【1】基础概念

文章目录 一、特点二、基础语法注意三、官方编程指南四、go 语言标准库 API 一、特点 golang 一个 go 文件都要归属到一个包&#xff0c;需要进行申明。天然的并发&#xff1a;golang 从语言层面支持大并发。每个 go 文件都必须要归属到一个包中。执行 go 文件&#xff1a;go …...

HTML 文档规范与解析模式:DOCTYPE、<html> 标签以及结构化页面

文章目录 `<!DOCTYPE html>` 文档类型声明标准模式与怪异模式HTML5 的简化声明`<html>` 标签`<head>` 标签`<body>` 标签小结<!DOCTYPE html> 文档类型声明 在 HTML 文档中,<!DOCTYPE html> 是一个重要的文档类型声明,主要用于告知浏览…...

大模型微调技术 --> 脉络

Step1:脉络 微调技术从最早期的全模型微调演变成如今的各种参数高效微调(PEFT)方法&#xff0c;背后是为了应对大模型中的计算、存储和数据适应性的挑战 1.为什么有微调&#xff1f; 深度学习模型越来越大&#xff0c;尤其是 NLP 中的预训练语言模型(BERT, GPT)系列。如果从…...

不要只知道deepl翻译,这里有10个专业好用的翻译工具等着你。

deepl翻译的优点还是有很多的&#xff0c;比如翻译的准确性很高&#xff0c;支持翻译的语言有很多&#xff0c;并且支持翻译文件和文本。但是现在翻译工具那么多&#xff0c;大家需要翻译的场景也有很多&#xff0c;怎么能只拥有一个翻译工具呢。所以在这里我帮助大家寻找了一波…...

第二节 管道符、重定向与环境变量

1.重定向技术的 5 种模式 &#xff08;1&#xff09;标准覆盖输出重定向 &#xff08;2&#xff09;标准追加输出重定向 &#xff08;3&#xff09;错误覆盖输出重定向 &#xff08;4&#xff09;错误追加输出重定向 &#xff08;5&#xff09;输入重定向2.输入输出重定向 输入…...

Linux 服务器使用指南:从入门到登录

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; &#x1f6a9;博主致力于用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 目录 一…...

QT 如何使QLabel的文字垂直显示

想要实现QLabel文字的垂直显示&#xff0c;可以通过使用“文字分割填充换行符”的方式来实现QLabel文字垂直显示的效果&#xff0c;下面是效果图&#xff1a; 具体实现代码&#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow:…...

蓬勃发展:移动开发——关于软件开发你需要知道些什么

一、前言 移动开发一直都是软件开发领域中最有趣的领域之一&#xff0c;这是因为&#xff1a; 1、移动开发为“只有一个人”的开发团队提供了一个非常独特的机会&#xff0c;让他可以在相对较短的时间内建立一个实际的、可用的、有意义的应用程序&#xff1b; 2、移动开发也代…...

1095. 山脉数组中查找目标值

目录 题目解法lambda在这是怎么用的&#xff1f; 题目 &#xff08;这是一个 交互式问题 &#xff09; 你可以将一个数组 arr 称为 山脉数组 当且仅当&#xff1a; arr.length > 3 存在一些 0 < i < arr.length - 1 的 i 使得&#xff1a; arr[0] < arr[1] <…...

【深度学习】InstantIR:图片高清化修复

InstantIR——借助即时生成参考的盲图像修复新方法 作者:Jen-Yuan Huang 等 近年来,随着深度学习和计算机视觉技术的飞速发展,图像修复技术取得了令人瞩目的进步。然而,对于未知或复杂退化的图像进行修复,仍然是一个充满挑战的任务。针对这一难题,研究者们提出了 Insta…...

推荐一款PowerPoint转Flash工具:iSpring Suite

iSpring Suite是一款PowerPoint转Flash工具&#xff0c;使用iSpring Suite 8可以轻松的将PPT演示文档转换为对Web友好的Flash影片格式。软件界面简洁&#xff0c;使用方便。为什么要转换成flash格式呢?Flash格式的最大特点是体积小巧、易于分发&#xff0c;兼容所有的操作系统…...

如何搭建汽车行业AI知识库:定义+好处+方法步骤

在汽车行业&#xff0c;大型车企面临着员工众多、价值链长、技术密集和知识传播难等挑战。如何通过有效的知识沉淀与应用&#xff0c;提升各部门协同效率&#xff0c;快速响应客户咨询&#xff0c;降低销售成本&#xff0c;并开启体系化、可持续性的知识管理建设&#xff0c;成…...

创新材料科技:铜冷却壁助力高炉节能降耗

高炉用铜冷却壁是高炉内部的一种构件&#xff0c;通常用于高炉的炉身部分。它的主要功能是在高炉冶炼过程中冷却炉壁&#xff0c;以防止炉壁过热。铜冷却壁通常由铜制成&#xff0c;因为铜具有良好的导热性和耐腐蚀性&#xff0c;能够有效地将热量从高炉内部传导到外部&#xf…...

Proteus中单片机IO口外接LED输出低电平时,引脚却一直保持高电平的问题(已解决)

文章目录 前言解决方法后记 前言 一个排阻接八个 LED&#xff0c;方便又省事&#xff0c;但出现了P1端口输出低电平后&#xff0c;仿真引脚却一直显示红色保持高电平不变&#xff0c;用电压表测量显示 2V 左右。 这是仿真的问题&#xff0c;在用开发板时是不会遇到的&#xff…...

Obsidian vs Typora

引言 近来几日&#xff0c;自己也算是用了一段时间的Obsidian了&#xff0c;也是有资格来说一下使用感受了。当前感觉是自己未来很长一段时间将会一直使用Obsidian了。 Typora vs Obsidian Typora 优点 整体好看&#xff0c;简洁&#xff0c;所见即所得 缺点&#xff1a;…...

非线性数据结构之图

一、有向图&#xff08;Directed Graph&#xff09; 1. 定义 有向图是一个由顶点&#xff08;节点&#xff09;和有方向的边&#xff08;弧&#xff09;组成的图。在有向图中&#xff0c;每条边都有一个起点和一个终点&#xff0c;表示从一个顶点到另一个顶点的关系。 2. 特…...

vue3项目history模式部署404处理,使用 historyApiFallback 中间件支持单页面应用路由

vue3项目history模式部署404处理&#xff0c;使用 historyApiFallback 中间件支持单页面应用路由 在现代的 web 开发中&#xff0c;单页面应用&#xff08;SPA&#xff09;变得越来越流行。这类应用通常依赖于客户端路由来提供流畅的用户体验&#xff0c;但在服务器端&#xf…...

不同的科技查新机构之间有什么区别?

科技查新&#xff0c;作为一种确保科研项目新颖性、先进性的重要手段&#xff0c;在现代科研活动中扮演着至关重要的角色。然而&#xff0c;在众多提供科技查新服务的机构中&#xff0c;它们之间的区别究竟体现在哪些方面呢&#xff1f;本文将从服务内容、专业领域、权威性与客…...

Pycharm,2024最新专业版下载安装配置详细教程!

先来一段官方介绍&#xff0c;PyCharm是一种PythonIDE&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外&#xff0c;该IDE提供了一些高级功能…...

BERT预训练的MLM和NSP任务的损失函数都是什么?

引言 BERT预训练过程中包括两个主要任务:Masked Language Modeling(MLM) 和 Next Sentence Prediction(NSP)。 MLM损失函数: 在MLM任务中,模型需要根据上下文预测被MASK掉的词语。具体来说,输入序列中的一部分词语被随机MASK,模型需要依据未被MASK的词语来预测这些被MASK…...

微信发布测试版4.0,碰瓷NT版QQ?

不知有没有小伙伴发现&#xff0c;就在最近&#xff0c;微信推出了全新版本&#xff1a;4.0.0测试版本&#xff0c;张小龙&#xff0c;你在搞什么飞机? 有什么新活儿了嘛 记得上一次发布腾讯QQ的NT版本&#xff0c;在网上也是引发了不小的吐槽。很多网友戏称为“脑瘫”版本&am…...

数据库->视图

目录 一、视图 1.什么是视图 ​编辑 2.创建视图 1.语法 3.使用视图 4.视图的功能 1.屏蔽相关字段 2.对外提供统一访问规范 3.视图和真实表进行表连接查询 5.修改数据 6.注意事项 7.删除视图 1.语法 8.视图的优点 1. 简单性 2. 安全性 3. 逻辑数据独⽴性 4. 重…...

华为HarmonyOS打造开放、合规的广告生态 - 贴片广告

场景介绍 贴片广告是一种在视频播放前、视频播放中或视频播放结束后插入的视频或图片广告。 接口说明 接口名 描述 loadAd(adParam: AdRequestParams, adOptions: AdOptions, listener: AdLoadListener): void 请求单广告位广告&#xff0c;通过AdRequestParams、AdOptions…...

vue3 v-for循环子组件上绑定ref并且取值

vue3 v-for循环子组件上绑定ref并且取值 // 要循环的变量 const views ref([])// 数组存所有ref dom const itemsRef ref([])const refresh (index) > {// 取出ref dom子组件并且调用其方法itemsRef.value[index].initChart() }<div class"block" v-for&quo…...