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

【Redis】Lua脚本在Redis中的基本使用及其原子性保证原理

文章目录

    • 背景
    • 一、Eval
    • 二、EvalSHA
    • 三、Redis 对 Lua 脚本的管理
      • 3.1 script flush
      • 3.2 script exists
      • 3.3 script load
      • 3.4 script kill
    • 四、Lua在Redis中原子性执行的原理

背景

Lua 本身是一种轻量小巧的脚本语言,在Redis2.6版本开始引入了对Lua脚本的支持。通过在服务器中嵌入Lua环境,Redis客户端就可以使用Lua脚本,直接在服务器端原子地执行多个Redis命令。在Redis中Lua有两种执行方式:Eval和EvalSHA。

一、Eval

通过Redis内置的 Lua 解释器,可以使用 EVAL 命令(也可以使用redis-cli 的–eval 参数)对 Lua 脚本进行解析。需要注意的点是执行Lua也会使Redis阻塞。
在这里插入图片描述
Eval命令的执行过程主要可以分为三个步骤:

  • 根据客户端给定的Lua脚本,在Lua环境中定义一个Lua函数,Lua函数的名称实际上是f_为前缀加上脚本本身计算出来的SHA1值组成,如f_ddfsdfjgjbg33rndgj00,SHA1的长度是40字符,而函数体则是脚本本身。
  • 将客户端给定的脚本保存到lua_scripts字典,简单来说就是添加一个key-value,key就是Lua脚本的SHA1校验和,而值是Lua脚本本身,这主要是用于以后使用。
  • 执行第一步在Lua环境中定义的函数,以此来执行客户端中给定的Lua脚本。

在Redis中,使用了Key列表和参数列表来为Lua脚本提供更多的灵活性,执行Eval命令的格式为:

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

栗子1:

eval "return 'hello lua'" 0

栗子2:

127.0.0.1:6379> eval 'return "hello " .. KEYS[1] .. ARGV[1]' 1 redis world执行返回:"hello world"

二、EvalSHA

EvalSHA 中方式的是拆分成两个步骤,首先要将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验码。然后使用EvalSHA命令使用SHA1作为参数可以直接执行对应Lua脚本。这样做的好处是可以避免每次发送Lua脚本的开销,而脚本也会常驻在服务端,脚本功能得到了复用。缺点是要怎么管理这些脚本和命令过多的话会占用Redis的内存。
在这里插入图片描述
在介绍Eval命令执行过程中,第一步会在Lua环境中生成一个Lua脚本对应的函数,形如:f_dfdugndgub320433,只要脚本对应的函数在Lua中定义过,那么即使不知道脚本的内容本身,客户端也是可以根据脚本的SHA1来调用脚本对应的函数,从而达到执行脚本的目的,这也就是EvalSHA命令的实现原理。

EvalSHA命令的一般格式:

evalsha sha1值 key个数 key列表 参数列表

如:

eval "return 'hello lua'" 0
// 执行完eval后,Lua环境就定义了一个函数名为:f_dfaujjgdgu388vdf83803(),那么就可以根据对应的sha1值来调用函数了。
evlsha "dfaujjgdgu388vdf83803" 0

三、Redis 对 Lua 脚本的管理

除了Eval和EvalSHA命令之外,Redis中与Lua脚本相关的命令还有:script flushscript existsscript load以及script kill

3.1 script flush

script flush命令用于清除服务器中的所有和Lua脚本相关的信息,这个命令会释放并重建lua_scripts字典,关闭现有的Lua环境并重建一个新的Lua环境。

命令格式:

script flush

栗子:

127.0.0.1:6379> script flush
OK

3.2 script exists

script exists命令会根据输入的SHA1校验和,检查校验和对应的脚本是否存在于服务器中。该命令主要是通过检查给定的SHA1是否存在于lua_scripts字典来实现的。

命令格式:

script exists sha1[sha1…]

返回结果代表 sha1[sha1…]被加载到 Redis 内存的个数。

栗子:

127.0.0.1:6379> script exists 5ea77eda7a16440abe244e6a88fd9df204ecd5aa
1) (integer) 1

3.3 script load

script load命令和Eval命令执行Lua脚本的前两步完全一样,该命令首先在Lua环境中创建相对应的函数,然后再将脚本保存到lua_scripts字典中。

命令格式:

script load lua脚本

栗子:

127.0.0.1:6379> script load "return 'hello lua'"
"5ea77eda7a16440abe244e6a88fd9df204ecd5aa"

3.4 script kill

如果Lua脚本比较耗时,甚至Lua脚本存在问题,那么此时Lua脚本的执行会阻塞Redis,直到脚本执行完毕或 者外部进行干预将其结束,就可以使用script kill来杀掉正在执行的 Lua 脚本。

举个栗子:

## 写一个死循环的lua脚本并在redis客户端执行
127.0.0.1:6379> eval 'while 1==1 do end' 0
## 重新起一个客户端去执行命令,返回了报错信息,此时Redis已经阻塞,无法处理正常的调用,这时可以选择继续等待。
## 但更多时候需要快速将脚本杀掉。使用shutdown save显然不太合适,所以选择script kill,当script kill执行之后,客户端调用会恢复
127.0.0.1:6379> get test
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
## 另起一个客户端,停止脚本执行
127.0.0.1:6379> script kill
OK
127.0.0.1:6379> get k1
"11"

此外,Redis提供了一个lua-time-limit参数,用于配置Lua脚本执行的超时时间,当 Lua 脚本时间超过lua-time-limit后,向其他命令调用发送BUSY的信号,并不会停止掉服务端和客户端的脚本执行,所以当某个Lua脚本执行达到lua-time-limit值之后,其他客户端在执行正常的命令时,将会收到“Busy Redis is busy running a script”错误,并且提示使用script kill或者shutdown nosave命令来杀掉这个 busy 的脚本。

实际上,如果Redis服务端设置了lua-time-limit参数,那么在每次执行Lua脚本之前,服务器都会在Lua环境里面设置一个超时的处理钩子(hook)。超时处理钩子再脚本运行期间,会定期检查脚本已经运行了多长时间,一旦钩子发现脚本的运行时间已经超过了lua-time-limit设定的时长,那么钩子将定期在脚本运行的间隙中,查看是否有script kill或者shutdown nosave到达服务器。如果超时运行的脚本未执行过任何的写入操作,那么客户端可以通过script kill命令停止脚本的运行,并向执行该脚本的客户端发送一个错误回复。处理完script kill命令后服务器可以继续运行。
此外,如果超时脚本已经执行过写入操作,那么客户端只能用shutdown nosave命令来停止服务器,从而防止不合法的数据被写入。

四、Lua在Redis中原子性执行的原理

  在Redis中,Lua脚本能够保证原子性的主要原因还是Redis采用了单线程执行模型。也就是说,当Redis执行Lua脚本时,Redis会把Lua脚本作为一个整体并把它当作一个任务加入到一个队列中,然后单线程按照队列的顺序依次执行这些任务,在执行过程中Lua脚本是不会被其他命令或请求打断,因此可以保证每个任务的执行都是原子性的。

这块儿想要继续了解的可以参考:为什么Redis单线程却能支撑高并发?Redis6.0之后为什么又引入多线程?

在实际开发中,为了提高效率,通常我们能让lua脚本接收多个参数,一次发送到Redis服务端,还能将key进行整理,将相同slot的key放到同一批进行处理,这在性能优化中能减少网络传输的开销,同时也能并发的发送给Redis服务端。

相关文章:

【Redis】Lua脚本在Redis中的基本使用及其原子性保证原理

文章目录 背景一、Eval二、EvalSHA三、Redis 对 Lua 脚本的管理3.1 script flush3.2 script exists3.3 script load3.4 script kill 四、Lua在Redis中原子性执行的原理 背景 Lua 本身是一种轻量小巧的脚本语言,在Redis2.6版本开始引入了对Lua脚本的支持。通过在服务…...

汇编--int指令

中断信息可以来自CPU的内部和外部, 当CPU的内部有需要处理的事情发生的时候,将产生需要马上处理的中断信息,引发中断过程。在http://t.csdn.cn/jihpG,我们讲解了中断过程和两种内中断的处理。 这一章中, 我们讲解另一种…...

生成式AI的JavScript技术栈

如果不使用新的软件基础设施技术,就很难理解它们。 至少,a16z 基础设施团队发现了这一点,而且因为我们中的许多人都是以程序员的身份开始职业生涯的,所以我们经常通过实践来学习。 尤其是生成式AI浪潮的情况尤其如此,它…...

从零开始学习软件测试-第39天笔记

接口测试 http消息结构 请求报文 请求行 请求方式 url 协议版本请求头空行请求体响应报文 响应行 协议版本 状态码 状态消息响应头空行响应体 请求参数类型 path参数 写在路径中的 https://xxx.xxx.com/参数值query参数 写在url问号后面,以键值对形式存在 h…...

【多思路附源码】2023高教社杯 国赛数学建模C题思路 - 蔬菜类商品的自动定价与补货决策

赛题介绍 在生鲜商超中,一般蔬菜类商品的保鲜期都比较短,且品相随销售时间的增加而变差, 大部分品种如当日未售出,隔日就无法再售。因此, 商超通常会根据各商品的历史销售和需 求情况每天进行补货。 由于商超销售的蔬…...

Vue2+Vue3基础入门到实战项目(六)——课程学习笔记

镇贴!!! day07 vuex的基本认知 使用场景 某个状态 在 很多个组件 来使用 (个人信息) 多个组件 共同维护 一份数据 (购物车) 构建多组件共享的数据环境 1.创建项目 vue create vuex-demo 2.创建三个组件, 目录如下 |-components |--Son1.…...

QT—基于http协议的网络文件下载

1.常用到的类 QNetworkAccessManager类用于协调网络操作,负责发送网络请求,创建网络响应 QNetworkReply类表示网络请求的响应。在QNetworkAccessManager发送一个网络请求后创建一个网络响应。它提供了以下信号: finished():完成…...

SpringBoot-配置优先级

配置 SpringBoot项目支持的三种格式的配置文件 application.properties:这是最常用的配置文件类型,使用键值对的形式来配置应用程序的属性。可以在该文件中配置应用程序的端口号、数据库连接信息、日志级别等。 application.yml:这是一种更…...

科普初步了解大模型

目录 一、大模型的简单认知 (一)官方定义 (二)聚焦到大语言模型 (三)大模型的应用举例 二、如何得到大模型 (一)整体的一般步骤 训练自己的模型 使用预训练模型 选择适当的…...

Nginx 和 网关的关系是什么

分析&回答 Nginx也可以实现网关,可以实现对api接口的拦截,负载均衡、反向代理、请求过滤等。网关功能可以进行扩展,比如:安全控制,统一异常处理,XXS,SQL注入等;权限控制,黑白名…...

解决springboot项目中的groupId、package或路径的混淆问题

对于像我一样喜欢跳跃着学习的聪明人来说,肯定要学springboot,什么sevlet、maven、java基础,都太老土了,用不到就不学。所以古代的聪明人有句话叫“书到用时方恨少”,测试开源项目时,编译总是报错&#xff…...

Vmware 网络恢复断网和连接

如果你的 虚拟机无法联网了,比如: vmware 无法将网络更改为桥接状态: 没有未桥接的主机网络适配器 等各种稀奇古怪的问题; 按照下面操作 还远默认设置 包你解决各种问题!...

学生来看!如何白嫖内网穿透?点进来!

文章目录 前言本教程解决的问题是:按照本教程方法操作后,达到的效果是前排提醒: 1 搭建虚拟机1.1 下载文件vmvare虚拟机安装包1.2 安装VMware虚拟机:1.3 解压虚拟机文件1.4 虚拟机初始化1.5 没有搜索到解决方式:1.6 虚…...

C++中的stack和queue

文章目录 1. stack的介绍和使用1.1 stack的介绍1.2 stack的使用 2. queue的介绍和使用2.1 queue的介绍2.2 queue的使用 3 priority_queue的介绍和使用3.1 priority_queue的介绍3.2 priority_queue的使用 4. 容器适配器4.1 什么是适配器4.2 STL标准库中stack和queue的底层结构4.…...

Ubuntu-22.04通过RDP协议连接远程桌面

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、RDP是什么?二、配置1.打开远程桌面功能2.验证服务3.防火墙配置4.测试效果 总结 前言 由于一些特殊需要,我需要通过远程桌面连接到U…...

20230908java面经整理

1.cpp和java的区别 cpp可以多重继承,对表java中的实现多个接口 cpp支持运算符重载、goto、默认函数参数 cpp自动强转,导致不安全;java必须显式强转 java提供垃圾回收机制,自动管理内存分配,当gc要释放无用对象时调用f…...

uniapp 开发App 网络异常如何处理

我对该问题思考的不是很清楚,目前只想到了基本的解决方案 第一、客户端的网络异常(断网) 1. 断网情况 一定要弹出信息提示,目前最好的解决方式就是在uni.request封装的统一方法中写提示 //1. 封装的网络请求 async function se…...

docker安装常用软件

Linux系统安装docker请参考:https://mp.csdn.net/mp_blog/creation/editor/128176825 docker安装mysql 1、拉镜像:docker pull mysql:8.0.26 2、创建数据目录: mkdir -p /mnt/data/mysql/data mkdir -p /mnt/data/mysql/logs mkdir -p /mn…...

CocosCreator3.8研究笔记(五)CocosCreator 脚本说明及使用(下)

在Cocos Creator中,脚本代码文件分为模块和插件两种方式: 模块一般就是项目的脚本,包含项目中创建的代码、引擎模块、第三方模块。 插件脚本,是指从 Cocos Creator 属性检查器中导入的插件,一般是引入第三方引入库文件…...

Adobe Acrobat Reader界面改版 - 解决方案

问题 日期:2023年9月 Adobe Acrobat Reader下文简称Adobe PDF Reader,此软件会自动进行更新,当版本更新至2023.003.20284版本后。 软件UI界面会大改版:书签页变成了右边、工具栏变到了左边、缩放按钮变到了右下角,如…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

python/java环境配置

环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...