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

分布式锁优化之 使用lua脚本改造分布式锁保证判断和删除的原子性(优化之LUA脚本保证删除的原子性)

文章目录

  • 1、lua脚本入门
    • 1.1、变量:弱类型
    • 1.2、流程控制
    • 1.3、在lua中执行redis指令
    • 1.4、实战:先判断是否自己的锁,如果是才能删除
  • 2、AlbumInfoApiController --》testLock()
  • 3、AlbumInfoServiceImpl --》testLock()

1、lua脚本入门

Lua 教程 | 菜鸟教程:https://www.runoob.com/lua/lua-tutorial.html\

redis提供了一组命令行直接可以执行lua脚本。
redis中的lua脚本是有原子性:因为是通过一个指令执行的

[root@localhost ~]# docker exec -it spzx-redis redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> eval script numkeys key [key ...] arg [arg ...]

script:lua 脚本字符串
numkeys:需要传递的key列表的元素数量
key:指定具体key列表,元素之间用空格区分,用KEYS[Iindex从1开始]
arg:指定具体arg列表,元素之间用空格区分,用ARGV[index从1开始]

127.0.0.1:6379> eval "return 'hello world!'" 0
"hello world!"

1.1、变量:弱类型

全局变量:a = 5
局部变量:local a = 5   redis中的lua脚本只支持局部变量
127.0.0.1:6379> eval "local a=5 return a" 0
(integer) 5

1.2、流程控制

127.0.0.1:6379> eval "if 10>20 then return 10 else return 20 end" 0
(integer) 20

要修正你的脚本,你应该使用 KEYS 和 ARGV 而不是 keys 和 argv(注意大小写)。KEYS 数组包含了传递给脚本的键名(key names),而 ARGV 数组包含了传递给脚本的参数(arguments)。

127.0.0.1:6379> eval "if keys[1]>argv[1] then return keys[2] else return argv[2] end" 2 10 20 30 40
(error) ERR Error running script (call to f_6913b8a1459b5bd1de1628cd76db221048464f0a): @enable_strict_lua:15: user_script:1: Script attempted to access nonexistent global variable 'keys'
127.0.0.1:6379> eval "if KEYS[1]>ARGV[1] then return KEYS[2] else return ARGV[2] end" 2 10 20 30 40
"40"
127.0.0.1:6379> eval "return {10,20,30,40}" 0
1) (integer) 10
2) (integer) 20
3) (integer) 30
4) (integer) 40
127.0.0.1:6379> eval "return {KEYS[1],KEYS[3],ARGV[1],ARGV[3]}" 4 10 20 30 40 50 60 70 80 90 
1) "10"
2) "30"
3) "50"
4) "70"

1.3、在lua中执行redis指令

redis.call(‘指令名称’,…)

127.0.0.1:6379> eval "return redis.call('set','lock','333')" 0
OK
127.0.0.1:6379> get lock
"333"
127.0.0.1:6379> eval "return redis.call('get','lock')" 0
"333"
127.0.0.1:6379> eval "return redis.call('set',KEYS[1],ARGV[1])" 1 lock 123
OK
127.0.0.1:6379> get lock
"123"

1.4、实战:先判断是否自己的锁,如果是才能删除

eval "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"
eval "if redis.call('get',KEYS[1]) == ARGV[1] 
then return redis.call('del',KEYS[1]) 
else return 0 
end"
127.0.0.1:6379> eval "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock 4343323
(integer) 0

在这里插入图片描述

127.0.0.1:6379> eval "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock 123
(integer) 1

在这里插入图片描述

2、AlbumInfoApiController --》testLock()

@Tag(name = "专辑管理")
@RestController
@RequestMapping("api/album/albumInfo")
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoApiController {@GetMapping("test/lock")public Result testLock() {this.albumInfoService.testLock();return Result.ok("测试分布式锁案例");}}

3、AlbumInfoServiceImpl --》testLock()

    @Overridepublic  void testLock(){// 加锁:set k v nx ex 3String uuid = UUID.randomUUID().toString();Boolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);if (!lock) {try {// 获取锁失败,进行自旋Thread.sleep(50);this.testLock();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {// 获取锁成功,执行业务//this.redisTemplate.expire("lock", 3, TimeUnit.SECONDS);Object numObj = this.redisTemplate.opsForValue().get("num");if (numObj == null) {this.redisTemplate.opsForValue().set("num", 1);return;}Integer num = Integer.parseInt(numObj.toString());this.redisTemplate.opsForValue().set("num", ++num);// 解锁// 先判断是否是自己的锁,如果是则删除//if (StringUtils.equals(uuid, this.redisTemplate.opsForValue().get("lock").toString())) {//    this.redisTemplate.delete("lock");//}String script = "if redis.call('get',KEYS[1]) == ARGV[1] " +"then " +"return redis.call('del',KEYS[1]) " +"else " +"return 0 " +"end";this.redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList("lock"), uuid);}}

在这里插入图片描述
压力测试肯定也没有问题。自行测试
启动多个运行实例:
在这里插入图片描述
在这里插入图片描述
redis中的值重新改为0。

[root@localhost ~]# ab -n 5000 -c 100 http://192.168.74.1:8500/api/album/albumInfo/test/lock
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 192.168.74.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requestsServer Software:        
Server Hostname:        192.168.74.1
Server Port:            8500Document Path:          /api/album/albumInfo/test/lock
Document Length:        76 bytesConcurrency Level:      100
Time taken for tests:   49.543 seconds
Complete requests:      5000
Failed requests:        674(Connect: 0, Receive: 0, Length: 674, Exceptions: 0)
Write errors:           0
Total transferred:      2353370 bytes
HTML transferred:       383370 bytes
Requests per second:    100.92 [#/sec] (mean)
Time per request:       990.856 [ms] (mean)
Time per request:       9.909 [ms] (mean, across all concurrent requests)
Transfer rate:          46.39 [Kbytes/sec] receivedConnection Times (ms)min  mean[+/-sd] median   max
Connect:        0    2   2.6      1      81
Processing:     5  948 2587.5     14   33884
Waiting:        5  948 2587.5     14   33883
Total:          6  950 2587.7     16   33887Percentage of the requests served within a certain time (ms)50%     1666%    19775%    62780%   105490%   284695%   501198%   827799%  12678100%  33887 (longest request)

在这里插入图片描述

相关文章:

分布式锁优化之 使用lua脚本改造分布式锁保证判断和删除的原子性(优化之LUA脚本保证删除的原子性)

文章目录 1、lua脚本入门1.1、变量&#xff1a;弱类型1.2、流程控制1.3、在lua中执行redis指令1.4、实战&#xff1a;先判断是否自己的锁&#xff0c;如果是才能删除 2、AlbumInfoApiController --》testLock()3、AlbumInfoServiceImpl --》testLock() 1、lua脚本入门 Lua 教程…...

从安防视频监控行业发展趋势看EasyCVR平台如何驱动行业智能升级

一、市场规模持续增长 随着科技的进步和社会安全意识的提升&#xff0c;安防视频监控行业市场规模持续增长。据市场研究数据显示&#xff0c;全球智能视频监控市场规模已超过千亿美元&#xff0c;并有望在未来几年内保持高速增长。在中国市场&#xff0c;随着智慧城市、工业互…...

TIOBE 编程指数 9 月排行榜公布 VB.Net第七

原文地址&#xff1a;百度安全验证 IT之家 9 月 8 日消息&#xff0c;TIOBE 编程社区指数是一个衡量编程语言受欢迎程度的指标&#xff0c;评判的依据来自世界范围内的工程师、课程、供应商及搜索引擎&#xff0c;今天 TIOBE 官网公布了 2024 年 9 月的编程语言排行榜&#xf…...

如何用ChatGPT制作一款手机游戏应用

有没有想过自己做一款手机游戏&#xff0c;并生成apk手机应用呢&#xff1f;有了人工智能&#xff0c;这一切就成为可能。今天&#xff0c;我们就使用ChatGPT来创建一个简单的井字棋游戏&#xff08;Tic-Tac-Toe&#xff09;&#xff0c;其实这个过程非常轻松且高效。 通过Cha…...

0基础学前端 day4

大家好&#xff0c;欢迎来到无限大的频道。 今天继续带领大家开始0基础学前端。 一、 什么是Bootstrap框架&#xff1f; Bootstrap是一个开源前端框架&#xff0c;于2011年由Twitter的开发团队开发并发布。其主要目的是简化开发过程&#xff0c;并使开发者能够轻松快速地构建…...

功能测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、测试项目启动与研读需求文档 &#xff08;一&#xff09; 组建测试团队 1、测试团队中的角色 2、测试团队的基本责任 尽早地发现软件程序、系统或产品中所…...

<Java>String类型变量的使用

两边有一个string就是连接&#xff0c;否则做加法 ‘ ’是char&#xff0c;“ ”是string&#xff0c;char能做加法&#xff0c;string只能连接...

JavaScript可视化

JavaScript 提供了多种库和工具来进行数据可视化。以下是一些流行的可视化库及其特点: D3.js特点: 强大的数据驱动文档(Data-Driven Documents)库,允许创建复杂的交互式图表。使用场景: 适合需要高度自定义和复杂交互的可视化。Chart.js特点: 易于使用的图表库,提供了多种…...

HTML5简介的水果蔬菜在线商城网站源码系列模板3

文章目录 1.设计来源1.1 主界面1.2 商品列表1.3 商品信息1.4 购物车1.5 其他页面效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.ne…...

传输层TCP协议

一、TCP协议格式 我们看到报头固定有20字节&#xff0c;最后选项大小不固定。 4位首部长度&#xff08;二进制0000 ~ 1111&#xff0c;十进制范围[0, 15]&#xff09;单位是4字节&#xff08;存放字节大小范围[0, 60]&#xff09;包括了20字节固定长度 选项长度。若选项大小为…...

自己开发一个网站系列之-网页开发初识

自己开发一个网站系列之-网页开发初识 欢迎来到网页开发的世界&#xff01;在这个教程中&#xff0c;我们将介绍网页开发的基本概念、工具和技术&#xff0c;让你能够从零开始创建自己的网页。 一、基础概念 1. 什么是网页&#xff1f; 网页是通过互联网进行访问的文档&#…...

【代码随想录训练营第42期 Day61打卡 - 图论Part11 - Floyd 算法与A * 算法

目录 一、Floyd算法与A * 算法 1、Floyd算法 思想 伪代码 2、 A * 算法 思想 伪代码 二、经典题目 题目一&#xff1a;卡码网 97. 小明逛公园 题目链接 题解&#xff1a;Floyd 算法 题目二&#xff1a;卡码网 127. 骑士的攻击 题目链接 题解&#xff1a;A * 算法&a…...

docker和ufw冲突问题

在ubuntu上部署的docker映射的端口&#xff0c;开启防火墙ufw后&#xff0c;在未放通的状态下&#xff0c;还是可以访问 解决办法&#xff1a; 在/etc/docker/daemon.json添加如下配置 {"iptables": false } 然后重启docker服务即可 systemctl daemon-reload s…...

Java(基本数据类型)( ̄︶ ̄)↗

Java 基本数据类型是Java编程语言中用于存储数据值的基本单位。它们直接映射到硬件的处理器上&#xff0c;因此访问速度非常快。Java中的基本数据类型分为四大类&#xff1a;整型、浮点型、字符型、布尔型。每种类型都有其固定的范围和存储大小。 一、整型 1&#xff09;byte…...

283. 移动0

class Solution(object):def moveZeroes(self, nums):""":type nums: List[int]:rtype: None Do not return anything, modify nums in-place instead."""# 两个指针&#xff0c;left, right,中间夹的都是0&#xff0c;# 像个虫子一样一纵一纵的…...

Mysql删库跑路,如何恢复数据?

问题 删库跑路&#xff0c;数据还能恢复吗&#xff1f; 我们经常听说某某被领导训斥了&#xff0c;对领导心生痛恨&#xff0c;然后登录 Mysql 删库跑路。对于闲聊中经常听说过的一个段子&#xff0c;在现实生活中是否真的发生过&#xff0c;如果发生了&#xff0c;我们该如何解…...

【HarmonyOS】应用引用media中的字符串资源如何拼接字符串

【HarmonyOS】应用引用media中的字符串资源如何拼接字符串 一、问题背景&#xff1a; 鸿蒙应用中使用字符串资源加载&#xff0c;一般文本放置在resoutces-base-element-string.json字符串配置文件中。便于国际化的处理。当然小项目一般直接引用字符串&#xff0c;不需要加载s…...

打开ffmpeg编码器的时候报错:avcodec_open2()返回-22

[h264_v4l2m2m 0x555555617a00] Could not find a valid device [h264_v4l2m2m 0x555555617a00] cant configure encoder 前言&#xff1a;先做一个操作&#xff0c;查找编码器的时候&#xff0c;使用名字查找的方式&#xff1a; const AVCodec *avcodec_find_encoder_by_n…...

R包:ggheatmap热图

加载R包 # devtools::install_github("XiaoLuo-boy/ggheatmap")library(ggheatmap) library(tidyr)数据 set.seed(123) df <- matrix(runif(225,0,10),ncol 15) colnames(df) <- paste("sample",1:15,sep "") rownames(df) <- sapp…...

springboot实战学习(7)(JWT令牌的组成、JWT令牌的使用与验证)

接着上篇博客的学习。上篇博客是在基本完成用户模块的注册接口的开发以及注册时的参数合法性校验的基础上&#xff0c;基本完成用户模块的登录接口的主逻辑以及提到了问题&#xff1a;"用户未登录&#xff0c;需要通过登录&#xff0c;获取到令牌进行登录认证&#xff0c;…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

多元隐函数 偏导公式

我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式&#xff0c;给定一个隐函数关系&#xff1a; F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 &#x1f9e0; 目标&#xff1a; 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z​、 …...

React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?

系列回顾&#xff1a; 在上一篇《React核心概念&#xff1a;State是什么&#xff1f;》中&#xff0c;我们学习了如何使用useState让一个组件拥有自己的内部数据&#xff08;State&#xff09;&#xff0c;并通过一个计数器案例&#xff0c;实现了组件的自我更新。这很棒&#…...

基于Python的气象数据分析及可视化研究

目录 一.&#x1f981;前言二.&#x1f981;开源代码与组件使用情况说明三.&#x1f981;核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.&#x1f981;演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...