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

redis面试(七)初识lua加锁脚本

redisson

redisson如何来进行redis分布式锁实现的源码,基于redis实现各种各样的分布式锁的原理
https://redisson.org/ 这是官网
https://github.com/redisson/redisson/wiki/Table-of-Content 这是官方文档

开始 demo

  • 建一个普通的工程
  • 在pom.xml里引入依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.8.1</version>
</dependency>  
  • 参照官网构建RedissonClient,同时看看对应的配置
    由于要在测试多节点,所以我再两台虚拟机,配置了一下redis cluster集群,标准的三主三从配置。
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://192.168.1.1:7001")
.addNodeAddress("redis://192.168.1.1:7002")
.addNodeAddress("redis://192.168.1.1:7003")
.addNodeAddress("redis://192.168.2.2:7001")
.addNodeAddress("redis://192.168.2.2:7002")
.addNodeAddress("redis://192.168.2.2:7003");RedissonClient redisson = Redisson.create(config);
  • 简单用一下分布式锁的功能
RLock lock = redisson.getLock("anyLock");
lock.lock();
lock.unlock();RMap<String, Object> map = redisson.getMap("anyMap");
map.put("foo", "bar");  map = redisson.getMap("anyMap");
System.out.println(map.get("foo"));  

getLock()

点进getLock方法,可以看到如下

@Override
public RLock getLock(String name) {
return new RedissonLock(connectionManager.getCommandExecutor(), name);
}

getLock()方法的时候,获取到的Lock对象是RedissonLock对象,就可以了,里面封装了一个ConnectionManager里获取的一个CommandExecutor,CommandExecutor是什么东西?
既然是Connection开头的,里面一定是封装了一个跟redis之间进行通信的一个Cconnection连接对象,CommandExecutor,命令执行器,封装了一个redis连接的命令执行器,可以执行一些set、get redis的一些操作,用来执行底层的redis命令的

RedissonLock

在这个RedissonLock的构造函数里面,建议大家关注的一行代码,别的没什么,主要是一个internalLockLeaseTime的东西,跟watchdog看门狗有关系的
我们在RedissonLock里面打几个断点
在这里插入图片描述
还有一个是lock()和unlock()方法,既然调用了,肯定要看一下
在这里插入图片描述

再往后走到这里,可以看到,在默认情况下,加锁的时候,long leaseTime, TimeUnit unit,是没有的,-1和null,就代表着说,只要你加到了一把锁,就一定会永久性的持有这把锁,除非是你当前持有这把锁的机器宕机了,watchdog看门狗就会发现,然后就会释放锁,避免说永久性的一个死锁发生

再去下面142行看看tryAcquire()做了什么
在这里插入图片描述
这个里面的方法tryLockInnerAsync() 这个是核心
在这里插入图片描述

tryLockInnerAsync() 加锁lua脚本

先仔细看看这里面的一块绿色代码,明显不是java,其实这就是redis的lua脚本
在这里插入图片描述
来分析一下
if (redis.call(‘exists’, KEYS[1]) == 0) then,KEYS[1]一看就是我们设置的那个锁的名字,人家先执行了redis的exists的指令,判断一下,如果“anyLock”这个key不存在,那么就进行加锁,实际加锁的指令
"redis.call(‘hset’, KEYS[1], ARGV[2], 1); " +
"redis.call(‘pexpire’, KEYS[1], ARGV[1]); " +
"return nil; " +
hset,redis的一个指令,相当于是在redis的一个map数据结构里设置一个key value
这个map对象的名字是我们传的anyLock,然后里面的k-v键值对,k我们假设为lockState,v值呢,设置为了1
hset KEYS[1] ARGV[2] 1 转换我们传的指令后就是 hset anyLock lockState 1

pexpire KEYS[1] ARGV[1],设置一个key的过期时间
KEYS[1]其实可以理解为就是我们设置的那个key,“anyLock”,ARGV[1]其实就是一个这个key的过期时间,可能是默认的一个值,叫做30000毫秒,30s,很有可能是说的是,这个anyLock这个key对应的过期时间就是30秒

再往下的逻辑"if (redis.call(‘hexists’, KEYS[1], ARGV[2]) == 1) then " +
"redis.call(‘hincrby’, KEYS[1], ARGV[2], 1); " +
"redis.call(‘pexpire’, KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
判断名字为anyLock的这个map对象里面某个k-v键值对,key键假设为lockState,他的对应值是不是1,(上面的逻辑中可以看到),如果存在的话就把这个值用命令hincrby +1
hincrby KEYS[1] ARGV[2] 1,将anyLock这个map中的lockState这个key的值累加1
pexpire’, KEYS[1], ARGV[1]是又把这个对象设置了一下过期时间
最后的return redis.call(‘pttl’, KEYS[1]); 是返回当前还有多久就过期了

那总结一下这个加锁逻辑,我们都知道 redis中的map数据结构是键值对。
那么这个加锁的时候,就是先判断 我们定义的锁名称“anyLock” 这个map结构是否存在,如果不存在的话,就加一个默认的键值对 k-v,key=某个默认值 value=1
如果这个名为“anyLock”的map结构已经存在了,就把那个默认的键值对k-v,key=某个默认值 value+1

commandExecutor.evalWriteAsync()

OK分析完脚本,再点进这个方法来看看
在这里插入图片描述
因为现在用的是redis cluster,3主3从的模式,那么这里就有是要把key放在其中某一个master上去。
这里的第一行int slot = connectionManager.calcSlot(key);
取出来redis cluster的数量,我们都知道,redis cluster集群的节点,默认是16384个,slot的数量默认就是16384个。
那这第一行的操作就是根据key的hash值,来计算出这个key要落到应该要哪个slot节点上

下一行代码就很明显了,是根据slot节点获取到,这个slot是放在哪个master上的?
在这里插入图片描述
anyLock这个key,13434,算出来是这个slot,相当于是针对“anyLock”这个key计算出来一个hash值,然后将这个hash值对16384这个slot数量进行取模,int slot = connectionManager.calcSlot(key);
取模之后就可以拿到当前这个“anyLock”的key对应的是哪个slot
在这里插入图片描述
再回到getNodeSource()方法中看看MasterSlaveEntry
MasterSlaveEntry [masterEntry=[freeSubscribeConnectionsAmount=1, freeSubscribeConnectionsCounter=50, freeConnectionsAmount=32, freeConnectionsCounter=64, freezed=false, freezeReason=null, client=[addr=redis://192.168.1.1:7002], nodeType=MASTER, firstFail=0]]

redis://192.168.1.1:7002,编号为13434的slot所在的master是这台机器的这个端口对应的master实例
此时就是已经知道了,其实必须是将加锁的那段lua脚本,放到redis://192.168.1.1:7002这个master实例上去执行,完成加锁的操作

回过头看一下这里的代码
这里的逻辑很简单了,里面也没必要再去跟的很深了,这里大概就是上面我们分析的,拿着刚才生成的lua脚本去对应的master节点中执行脚本,把数据存入。
在这里插入图片描述
在这里插入图片描述

总结

总结一下,这里就是最基础的通过lua脚本加锁的逻辑,我们知道了redis加锁的时候是通过lua脚本将其传到redis中来加锁的。加锁的时候本质上就是新建了一个map类型的数据,key是我们的锁名称。

流程:

  • 判断key是否存在
    • 不存在的话新建一个map类型的数据,数据名称为锁名称
    • map中的数据只有一对k-v,key应该为加锁次数,默认value为1,这个主要用来做同一个线程多次加锁的重入操作
    • pexpire 命令设置过期时间,默认为30000ms 也就是30s
  • 存在的话
    • hincrby 命令,将map中的加锁次数 +1
    • pexpire 再次将过期时间设置为30000ms 也就是30s
  • pttl命令,返回当前数据的过期时间

相关文章:

redis面试(七)初识lua加锁脚本

redisson redisson如何来进行redis分布式锁实现的源码&#xff0c;基于redis实现各种各样的分布式锁的原理 https://redisson.org/ 这是官网 https://github.com/redisson/redisson/wiki/Table-of-Content 这是官方文档 开始 demo 建一个普通的工程在pom.xml里引入依赖 <…...

企元数智百年营销史的精粹:借鉴历史创造未来商机

随着时代的发展和科技的进步&#xff0c;传统营销方式正在经历前所未有的颠覆和改变。在这个数字化时代&#xff0c;企业需要不断创新&#xff0c;同时借鉴百年营销史的精粹&#xff0c;汲取历史经验&#xff0c;创造未来商机。而"企元数智"作为现代营销的代表&#…...

Java @SpringBootTest注解用法

SpringBootTest 是 Spring Framework 中的一个注解&#xff0c;用于指示 Spring Boot 应用程序的测试类。当你在测试类上使用 SpringBootTest 注解时&#xff0c;Spring Boot 会启动一个 Spring 应用程序上下文&#xff0c;并且加载应用程序的 application.properties 或 appli…...

构建智能招聘平台:人才招聘系统源码开发指南

本篇文章&#xff0c;小编将详细探讨如何基于人才招聘系统源码开发一个智能招聘平台&#xff0c;为企业的人才战略提供支持。 一、智能招聘平台的核心功能 智能招聘平台的核心在于提高招聘效率和匹配度&#xff0c;这需要集成多个关键功能模块&#xff1a; 1.职位发布与管理…...

Docker + Nacos + Spring Cloud Gateway 实现简单的动态路由配置修改和动态路由发现

1.环境准备 1.1 拉取Nacos Docker镜像 从Docker Hub拉取Nacos镜像&#xff1a; docker pull nacos/nacos-server:v2.4.01.2 生成密钥 你可以使用命令行工具生成一个不少于32位的密钥。以下是使用 OpenSSL 生成 32 字节密钥的示例&#xff1a; openssl rand -base64 321.3 …...

Linux中多线程压缩软件 | Mingz

原文链接&#xff1a;Linux中多线程压缩软件 本期教程 软件网址&#xff1a; https://github.com/hewm2008/MingZ安装&#xff1a; git clone https://github.com/hewm2008/MingZ.git cd MingZ make cd bin ./mingz -h使用源码安装&#xff1a; 若是你的git无法使用安装&am…...

【JavaEE精炼宝库】网络原理基础——UDP详解

文章目录 一、应用层二、传输层2.1 端口号&#xff1a;2.2 UDP 协议&#xff1a;2.2.1 UDP 协议端格式&#xff1a;2.2.2 UDP 存在的问题&#xff1a; 2.3 UDP 特点&#xff1a;2.4 基于 UDP 的应用层协议&#xff1a; 一、应用层 我们 Java 程序员在日常开发中&#xff0c;最…...

【回眸】周中WLB-个人

生活 计划 苏州or杭州or舟山 负负得正 烟火 鲜芋仙 办上海银行的银行卡 申请表材料准备好 个人博客提现签约变现 个人提升 yas补直播笔记&#xff08;听、口&#xff09;1~3课 *2倍 dy学堂 —— 3课时输出博客 个人笔记本搭建环境 副业探索 收集信息差 目前已…...

基于Spring boot + Vue的灾难救援系统

作者的B站地址&#xff1a;程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址&#xff1a;程序员云翼-CSDN博客 1.项目技术栈&#xff1a; 前后端分离的项目 后端&#xff1a;Springboot MybatisPlus 前端&#xff1a;Vue ElementUI 数据库&#xff1a; …...

C#进阶:轻量级ORM框架Dapper详解

C#进阶&#xff1a;轻量级ORM框架Dapper详解 在C#开发中&#xff0c;ORM&#xff08;对象关系映射&#xff09;框架是处理数据库交互的重要工具。Dapper作为一个轻量级的ORM框架&#xff0c;专为.NET平台设计&#xff0c;因其高性能和易用性而备受开发者青睐。本文将详细介绍D…...

【python015】常见成熟AI-图像识别场景算法清单(已更新)

1.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 【python015】常见成熟AI-图像识别场景算法清单及代码【python015】常见成熟AI-图像识别场景算法清单及代码【python015】常见成熟AI-图像识别场景算法清单及代码 文章目录 1.背景介绍2…...

删除有序数组中的重复项(LeetCode)

题目 给你一个 升序排列 的数组 &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 中唯一元素的个数。 考虑 的唯一元素的数量为 &#xff0c;你需要做以下事情确…...

【算法 03】雇佣问题

“雇用问题”及其算法优化 在日常生活和工作中&#xff0c;我们经常会遇到需要从多个选项中做出选择的情况&#xff0c;而“雇用问题”正是这样一个典型的例子。在这个问题中&#xff0c;我们不仅要考虑如何高效地找到最佳候选人&#xff0c;还要关注整个过程中的成本。今天&a…...

vue3+axios请求导出excel文件

在Vue 3中使用axios请求导出Excel文件&#xff0c;可以发送一个GET或POST请求&#xff0c;并设置响应类型为blob或arraybuffer&#xff0c;然后使用new Blob()构造函数创建一个二进制文件&#xff0c;最后使用URL.createObjectURL()生成一个可以下载的链接。 先看代码 import…...

LLM与NLP

大语言模型与自然语言处理的关系&#xff1a;整体与组成的关系如 自然语言理解的编码器式&#xff08;encoder-only&#xff09;的架构是语境相关的词表示BERT&#xff1b; 自然语言转换的编码器-解码器式的&#xff08;encoder-decoder&#xff09;的架构是词频-逆文档词频T…...

js 判断是否为回文串

需求&#xff1a;忽略英文大小写和空格差异&#xff0c;判断是否为回文字符串&#xff08;例如"我爱你 你爱我"&#xff0c;"abc bA"&#xff09; 思路&#xff1a;利用翻转字符串比较&#xff0c;利用循环双指针&#xff0c;利用递归或者双循环&#xf…...

多重背包c++

题目描述 有N种物品和一个容量是V的背包。 第i种物品最多有si件&#xff0c;每件体积是vi&#xff0c;价值是wi。 求解将哪些物品装入背包&#xff0c;可使物品体积总和不超过背包容量&#xff0c;且价值总和最大。 输出最大价值。 输入 第一行两个整数&#xff0c;N&#x…...

kernel input事件测试程序

测试内核input 事件测试程序。 getevent -lt 命令查看注册的是是event0/1/2/3/4 中的哪一个。 gcc input_test.c -o input_test 编译成可执行程序。将编译的input_test&#xff0c;U盘或ADB push到系统里面&#xff0c;chmod 777 input_test 在 ./input_test input_test.c #…...

gd32 i2c 中断 主机从机双向通信例程

Master I2C0_SCL PB8 AF4 I2C0_SDA PB9 AF4 Slave I2C1_SCL PB10 AF4 I2C1_SDA PB11 AF4 //主机中断发送 void i2c_master_transmit_it(uint32_t address, uint8_t* buff, uint32_t size); //主机中断接收 void i2c_master_receive_it(uint32_t address, uint8_t* buff, uint…...

程序员在AI时代:重塑核心竞争力,共舞智能未来

程序员在AI时代&#xff1a;重塑核心竞争力&#xff0c;共舞智能未来 在这个日新月异的科技时代&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术&#xff0c;尤其是以ChatGPT、Midjourney、Claude等为代表的大语言模型&#xff0c;正以前所未有的速度渗透到编程…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

ABAP设计模式之---“Tell, Don’t Ask原则”

“Tell, Don’t Ask”是一种重要的面向对象编程设计原则&#xff0c;它强调的是对象之间如何有效地交流和协作。 1. 什么是 Tell, Don’t Ask 原则&#xff1f; 这个原则的核心思想是&#xff1a; “告诉一个对象该做什么&#xff0c;而不是询问一个对象的状态再对它作出决策。…...

Web APIS Day01

1.声明变量const优先 那为什么一开始前面就不能用const呢&#xff0c;接下来看几个例子&#xff1a; 下面这张为什么可以用const呢&#xff1f;因为复杂数据的引用地址没变&#xff0c;数组还是数组&#xff0c;只是添加了个元素&#xff0c;本质没变&#xff0c;所以可以用con…...

Qt 按钮类控件(Push Button 与 Radio Button)(1)

文章目录 Push Button前提概要API接口给按钮添加图标给按钮添加快捷键 Radio ButtonAPI接口性别选择 Push Button&#xff08;鼠标点击不放连续移动快捷键&#xff09; Radio Button Push Button 前提概要 1. 之前文章中所提到的各种跟QWidget有关的各种属性/函数/方法&#…...

JVM——对象模型:JVM对象的内部机制和存在方式是怎样的?

引入 在Java的编程宇宙中&#xff0c;“Everything is object”是最核心的哲学纲领。当我们写下new Book()这样简单的代码时&#xff0c;JVM正在幕后构建一个复杂而精妙的“数据实体”——对象。这个看似普通的对象&#xff0c;实则是JVM内存管理、类型系统和多态机制的基石。…...

智慧城市项目总体建设方案(Word700页+)

1 背景、现状和必要性 1.1 背景 1.1.1 立项背景情况 1.1.2 立项依据 1.2 现状 1.2.1 党建体系运行现状 1.2.2 政务体系运行现状 1.2.3 社会治理运行现状 1.2.4 安全监管体系现状 1.2.5 环保体系运行现状 1.2.6 城建体系运行现状 1.2.7 社区体系运行现状 1.2.8 园区…...