分布式锁优化之 使用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)

在这里插入图片描述

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

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

相关文章

Linux基础命令以及常识

镜像站点服务器&#xff08;相当于下载的网址&#xff09;也可叫软件源 vim /etc/apt/sources.list 索引文件(网络服务器在本地的缓存) 服务器软件源在本地列出来一个清单&#xff0c;以便于主机进行查询操作 cd /var/lib/apt/lists/ 下载软件包默认存放路径 cd /var/cache/a…

认识NDK

什么是NDK&#xff08;Native Development Kit&#xff09; The Android NDK is a toolset that lets you implement parts of your app in native code, using languages such as C and C. &emdp; Android NDK 是一个工具集&#xff0c;可让您使用 C 和 C 等语言以原生代…

重型工程车辆数据集

重型工程车辆数据集&#xff0c;内含Bull_dozer&#xff08;推土机&#xff09;, Dumb_truck&#xff08;卡车&#xff09;, Excavator&#xff08;挖掘机&#xff09;, Grader&#xff08;平地机&#xff09;, Loader&#xff08;转载机&#xff09;, Mobile_crane&#xff08…

『功能项目』QFrameWork拾取道具UGUI【69】

本章项目成果展示 我们打开上一篇68QFrameWork扔到地上UGUI的项目&#xff0c; 本章要做的事情是实现当物品在地上时&#xff0c;点击物品将对应物品转移到道具栏中 制作一个提示UI界面 添加Button组件设置为点击即将父物体隐藏 拖拽到文件夹中在场景中删除 创建脚本&#xf…

架构师:使用 Zookeeper 实现分布式锁的技术指南

1、简述 在分布式系统中,多个节点可能需要访问共享资源或执行需要互斥的操作,为了避免竞争导致数据不一致或资源争用,我们需要一种机制来协调各个节点对资源的访问。分布式锁是用于解决这种竞争问题的关键技术,它确保在同一时间只有一个节点能够访问或修改共享资源。 2、Z…

Ansible部署与应用基础

由于互联网的快速发展导致产品更新换代速度逐步增长&#xff0c;运维人员每天都要进行大量的维护操作&#xff0c;按照传统方式进行维护使得工作效率低下。这时部署自动化运维就 可以尽可能安全、高效的完成这些工作。 一、Ansible概述 1.什么是Ansible Ansible 是基于 Pytho…

Matplotlib绘图基础

1、散点图 绘制散点图是数据可视化中非常常见的操作&#xff0c;它用于显示两组数据之间的关系。Matplotlib 提供了 plt.scatter() 函数&#xff0c;可以轻松绘制散点图。以下是一个基础的散点图示例代码&#xff0c;并包含了一些优化可视化呈现的技巧。 import matplotlib.p…

Python 如何调用讯飞星火大模型API

1 讯飞星火简介 讯飞星火是科大讯飞推出的一款先进的人工智能大模型&#xff0c;它具备强大的语言理解和知识问答能力&#xff0c;能够在多种场景中提供智能化服务。2024年6月27日&#xff0c;科大讯飞发布了讯飞星火大模型V4.0版本&#xff0c;全面对标GPT-4 Turbo。现有的模…

某采招网爬虫数据采集逆向

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 目标网站 aHR0cHM6Ly9zZWFyY2guYmlkY2VudGVyLmNvbS5jbi9zZWFyY2g/a2V5d29yZHM9JWU0…

医院伤员消费点餐限制———未来之窗行业应用跨平台架构

一、点餐上限 医院点餐上限具有以下几方面的意义&#xff1a; 1. 控制成本 - 有助于医院合理规划餐饮预算&#xff0c;避免食物的过度供应造成浪费&#xff0c;从而降低餐饮成本。 2. 保障饮食均衡 - 防止患者或陪护人员过度点餐某一类食物&#xff0c;有利于引导合…

基于51单片机的两路电压检测(ADC0808)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;通过ADC0808获取两路电压&#xff0c;通过LCD1602显示 二、硬件资源 基于KEIL5编写C代码&#xff0c;PROTEUS8.15进行仿真&#xff0c;全部资源在页尾&#xff0c;提供…

大数据Flink(一百二十三):五分钟上手Flink MySQL连接器

文章目录 五分钟上手Flink MySQL连接器 一、创建数据库表 二、​​​​​​创建session集群 三、源表查询 四、​​​​​窗口计算 五、​​​​​​结果数据写回数据库 五分钟上手Flink MySQL连接器 MySQL Connector可以将本地或远程的MySQL数据库连接到Flink中&#x…

【Spring Cloud Alibaba】Nacos

【Spring Cloud Alibaba】Nacos 1. 什么是Nacos&#xff0c;它都能干什么&#xff1f;1.1 注册中心演变及其思想1.2 Nacos Discovery1.3 远程调用流程图1.4 一个微服务的流程1.4 常用注册中心对比 2. Nacos Server部署3. Nacos Client搭建附录 1. 什么是Nacos&#xff0c;它都能…

科研绘图系列:R语言误差连线图(errobar linechart)

文章目录 介绍加载R包导入数据数据预处理画图系统信息介绍 误差连线图是一种在数据可视化中常用的图表,它通过在数据点处添加线段(误差线)来表示数据的变异性或不确定性。这些误差线可以基于不同的统计度量,如标准差(Standard Deviation)、标准误差(Standard Error)或…

docker操作的基本命令加容器的基本命令(仅供自己参考)

1、docker build&#xff1a;本地将一个docker文件打包成镜像 2、docker push&#xff1a;将自己打包的镜像传到镜像服务器上 3、docker pull&#xff1a;将镜像服务器上的镜像拉取到本地 4、docker images&#xff1a; 查看镜像服务器上的镜像 5、docker rmi&#xff1a;删…

lte sss加扰序列c产生 MATLAB和c语言实现

参考3GPP 36.211 今日给大家介绍一下LTE SSS信号产生过程中加扰序列c的产生过程以及用MATLAB 和 c语言给大家实现一下&#xff1a; 加扰序列c产生过程如下&#xff1a; 1 首先产生公共的序列x的生成 X的初始值 两个加扰序列c0和c1 c语言实现 void lte_sss_gen_c(char *c,u…

初始Vitis——ZYNQ学习笔记1

一、Vitis是什么 Vitis 统一软件平台的前身为 Xilinx SDK&#xff0c;从 Vivado 2019.2 版本开始&#xff0c; Xilinx SDK 开发环境已统一整合到全功能一体化的 Vitis 中。 Vitis 开发平台除了启动方式、软件界面、使用方法与 SDK 开发平台略有区别&#xff0c;其他操作几乎一模…

针对 Linux SSH 服务器的新攻击:Supershell 恶意软件危害易受攻击的系统

ASEC 研究人员发现了针对保护不善的 Linux SSH 服务器的新攻击。 在其中&#xff0c;黑客使用了用Go编写的 Supershell恶意软件。 该后门使攻击者能够远程控制受感染的系统。 初次感染后&#xff0c;黑客启动扫描仪来寻找其他易受攻击的目标。 据信这些攻击是使用从已受感…

【多模态大模型】Qwen2-VL基本原理和推理部署实战

文章目录 Qwen2-VL基本原理Qwen-VL简要回顾Qwen2-VL的高级升级统一视觉处理方式原生动态分辨率处理&#xff08;非大图切分方式&#xff09;多模态旋转位置编码 Qwen2-VL推理实现|代码解析单图推理视觉信息预处理找到能被28整除的最合适size最大最小pixel数边界处理 多模态信息…

docker入门总结(附错误处理,持续更新)

安装、启动、卸载 卸载掉旧版本的 Docker yum remove -y docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engineDocker安装&#xff08;选其一&#xff09;…