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

news2024/12/28 4:51:07

文章目录

    • 背景
    • 一、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服务端。

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

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

相关文章

高并发环境下压测故障

文章目录 一、高并发压测故障二、JVM 调优1. 堆内存调优2. 堆外内存调优 一、高并发压测故障 每次在大促之前,我们都需要对服务进行压测。而在压测期间,突然爆发了红灯告警,订单量直接少了一半,这是一次很严重的压测故障。首先看…

公司快递账单管理智能化教程

今时不同往日,企业寄件早已摆脱纸质面单,向更为便捷的电子面单过渡。众快递公司为了留住大客户,为其提供更好的服务,早早推出月结模式寄件。办公族应该不陌生,企业如果和快递公司签订月结协议的话,员工寄件…

SEO扫地僧站群·静态生成式养站王,万站秒建,批量养站神器介绍

扫地僧站群静态养站王,程序采用了"织梦CMS"式静态生成式的方式,只需要一个后台管理系统即可管理多个网站,大大提高了建站效率,程序可以适配各种采集器获得的内容,可以方便地实现内容的快速采集,程序支持实时统计和广告插入&#xf…

leetcode刷题--栈与递归

文章目录 1. 682 棒球比赛2. 71 简化路径3. 388 文件的最长绝对路径4. 150 逆波兰表达式求值5. 227. 基本计算器II6. 224. 基本计算器7. 20. 有效的括号8. 636. 函数的独占时间9. 591. 标签验证器10. 32.最长有效括号12. 341. 扁平化嵌套列表迭代器13. 394.字符串解码 1. 682 棒…

docker 部署vue

1: 首先部署nginx docker run --name nginx -d -p 88:80 nginx 2:访问 http://xxxxxxx:88/ 3: 进入nginx docker exec -it nginx /bin/sh 4: 回到vs,编译项目 npm run build 得到dist文件夹 5:创建docker 6: 将…

量化交易最新12篇顶会论文及开源代码汇总(WWW23、AAAI23、KDD23)

对比普通的交易方式,量化交易具有高效性、稳定性以及强风险控制能力,因此,量化交易在金融领域中已经得到了广泛的应用,目前已有许多大型投资机构和对冲基金将量化交易列为其投资组合的重要部分。 本次分享的是我从各大顶会中精选…

826. 安排工作以达到最大收益;2257. 统计网格图中没有被保卫的格子数;816. 模糊坐标

826. 安排工作以达到最大收益 核心思想:排序维护最大利润。首先我们需要对工人按照能力排序,前面工人满足的最大利润后面的工人肯定是满足的,所以我们只需要用一个tmp来维护小于等于当前工人的最大利润,然后如何得到tmp&#xff…

java.lang.Exception: No runnable methods

无可执行test方法异常,报错为: 1.查看是否添加了Test注解在执行的方法上 2.查看测试类的注解 3.查看test类的导包,一定要是junit的。

【SpringMVC】RESTful风格CRUD实现

目录 一、REST简介 1.1 什么是REST? 1.2 REST风格的优点 1.3 请求方式 二、构建项目 ⭐思路分析 2.1 环境准备 2.1.1 导入相关pom依赖 2.1.2 jdbc.properties:配置文件 2.1.3 配置代码生成器 generatorConfig.xml 2.1.4 spring与mybatis整合的配置文件 s…

开机性能-如何抓取开机systrace

一、理论 1.背景 抓取开机 trace 需要使用 userdebug 版本,而我们测试开机性能问题时都要求使用 user 版本,否则会有性能损耗问题。因此想要在抓取开机性能trace 时,需要在 user 版本上打开 atrace 功能之后才能抓取 trace,默认 …

什么是CE认证?CE认证如何办理?亚马逊欧洲站产品适用范围

什么是CE标志? CE标志是欧盟强制认证标志,代表着产品符合欧洲指令的基本要求。这意味着,只有经过认证并贴上CE标志,你的产品才能合法地进入欧洲市场销售。那么,如何让你的产品贴上CE标志呢?接着往下看。 如…

【刷题篇】贪心算法

文章目录 分割平衡字符串买卖股票的最佳时机Ⅱ跳跃游戏钱币找零 分割平衡字符串 class Solution { public:int balancedStringSplit(string s) {int lens.size();int cnt0;int balance0;for(int i0;i<len;i){if(s[i]R){balance--;}else{balance;}if(balance0){cnt;}}return …

作为程序员,如何快速上手项目

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 本节从“道、术、器”三个方面为大家分享程序员如何快速上手项目。 1 道 道&#xff0c;就是道理、规律&#xff0c;万事万物都有道&#xff0c;软件开发也有道。 软件开发…

strerror函数

目录 strerror 函数介绍&#xff1a; 举例&#xff1a; 使用案例&#xff1a; 优化&#xff1a; perror&#xff1a; strerror 函数介绍&#xff1a; 函数声明&#xff1a; char * strerror ( int errnum );头 文 件&#xff1a;#include <string.h>返 回 值&a…

基于 SpringBoot 的智慧养老平台,附源码、教程

文章目录 1.研究背景2. 技术栈3.系统分析4系统设计4.1 软件功能模块设计4.2数据库设计与实现 5系统详细设计5.1系统功能模块5.2后台登录功能5.2.1管理员功能 源码下载地址 1.研究背景 困扰管理层的许多问题当中,智慧养老平台一定是养老平台不敢忽视的一块。但是管理好智慧养老…

一.使用qt creator 设计显示GUI

一.安装qt creator 二.创建项目 文件-》新建项目 三.使用设计 可以直接使用鼠标拖拽 四.转换为py文件 # from123.py 为导出 py文件的文件名 form.ui 为 qt creator创造的 ui 文件 pyuic5 -o x:\xxx\from123.py form.ui五.显示GUI from PyQt5.QtWidgets import * fr…

【C进阶】指针(二)

六、函数指针数组 数组是一个存放相同类型数据的存储空间&#xff0c;我们已经学习了指针数组 eg&#xff1a; int *arr[10] //整形指针数组-数组-存放的是整形指针 char *arr[5] //字符指针数组-数组-存放的是字符指针 那么把函数的地址存到一个数组中&#xff0…

2023国赛A题保姆级思路代码:定日镜场的优化设计

A题是一套传统的机理分析加规划求解题&#xff0c;首先我们要根据每个月21号的特定时间点建立一个太阳角度框架&#xff0c;根据题目所给出的公式计算效率&#xff0c;还有输出的热功率&#xff0c;然后根据月份求解各种效率&#xff0c;再把年份进行汇总&#xff0c;二三题都是…

阿里国际、亚马逊等跨境电商平台做测评怎么避免踩坑?

由于跨境电商的卖家越来越多&#xff0c;测评逐渐成为众多卖家的关注焦点&#xff0c;在各个跨境电商平台上&#xff0c;随着店铺数量的增加&#xff0c;同一商品之间的竞争也日益激烈&#xff0c;不同于国内的电商平台&#xff0c;跨境电商平台很少提供与卖家客服进行沟通的机…

论文简读 LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

论文地址&#xff1a;https://arxiv.org/pdf/2106.09685.pdf 项目地址&#xff1a;https://github.com/microsoft/LoRA 全文翻译地址&#xff1a;https://zhuanlan.zhihu.com/p/611557340 本来想自行翻译的&#xff0c;但最近没有空 1、关键凝练 1.1 LORA是什么&#xff1f; …