Redis Lua脚本 Debug

news2024/11/28 16:03:53

Redis 编程接口之Lua脚本

Redis 使用Lua脚本和Redis Functions扩展其功能。Redis提供编程接口,允许开发者在服务器执行自定义的脚本,对于不同的版本,实现的方式略有不同

  • Redis 7 及以上版本 使用Redis Functions 管理、运行脚本
  • Redis 6.2及之前的版本 使用Lua脚本和EVAL命令对Redis 服务进行编程

首先,自Redis 2.6.0以来,EVAL命令支持运行服务器端脚本。Eval脚本提供了一种让Redis临时运行脚本的快速、直接的方法。然而,使用它们意味着脚本逻辑是应用程序的一部分(而不是Redis服务器的扩展)。运行脚本的每个应用程序实例必须具有随时可供加载的脚本源代码。这是因为脚本只由服务器缓存,并且是不稳定的。随着应用程序的增长,这种方法可能变得更难开发和维护。

其次,在Redis7.0中添加的Redis Functions本质上是数据库元素的脚本。因此,函数将脚本与应用程序逻辑分离,并支持脚本的独立开发、测试和部署。要使用函数,需要首先加载它们,然后所有连接的客户端都可以使用它们。在这种情况下,将函数加载到数据库成为一项管理部署任务(例如加载Redis模块),将脚本与应用程序分离。

只读脚本

只读脚本是只执行却并不修改Redis服务器中任何键命令的脚本。只读脚本通过添加 no-writes 标志来执行;或者执行任意只读命令(EVAL_RO,、EVALSHA_RO、 FCALL_RO)。只读脚本具有以下属性:

  • 只读脚本在副本上照样运行
  • 可以被SCRIPT KILL 命令杀死
  • Redis 内存超过限制时,不会因为OOM导致失败
  • 写入不会被阻塞,例如在协调故障切换期间发生的暂停
  • 无法执行任何可能修改数据集的命令
  • PUBLISH、SPUBLISH、PFCOUNT被认为是写入命令

执行时长

脚本的最大执行时间(默认设置为5秒),这个默认值在通常情况下是合理。一般的业务场景下,脚本的运行时长不超过一毫秒。这个限制是用来处理开发过程中意外产生的无限循环的。

可以通过CONFIG SET 命令;或者修改redis.conf中busy-reply-threshold属性来修改默认值。

当脚本达到超时阈值时,Redis不会自动终止脚本。这样做将违反Redis和脚本引擎之间的约定,后者确保脚本是原子的。

Lua脚本

初识lua

> EVAL "return 'Hello, scripting!'" 0
"Hello, scripting!"

在上面的示例中国,EVAL携带两个参数。第一个参数是由Lua源代码组成的字符串。第二个参数是lua脚本正文后面的参数序号,从第三个参数开始,表示Redis键名称。在本例中,我们使用了值0,因为我们没有为脚本提供任何参数。

脚本参数

redis> EVAL "return ARGV[1]" 0 Hello
"Hello"
redis> EVAL "return ARGV[1]" 0 Parameterization!
"Parameterization!"

Redis 服务器执行上下文通过KEYS、ARGV关键字为脚本提供参数。KEYS代表脚本中的 Redis 键信息;ARGV 关键字代表脚本中的参数信息。在上面的示例中,只有ARGV,因此整个lua脚本不需要填充键信息,因此指定数字为0;Hello和Parameterization!作为脚本的常规输入参数。

请看接下来的示例,需要输入2个键参数,因此参数后面接数字2,后续2个参数为键参数,其他参数为ARGV参数

redis> EVAL "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3] }" 2 key1 key2 arg1 arg2 arg3
1) "key1"
2) "key2"
3) "arg1"
4) "arg2"
5) "arg3"

Redis交互

可以通过在Lua脚本中调用Redis.call()、Redis.pcall()调用Redis命令。这两个命令的功能完全相同,都能通过动态参数执行Redis命令。区别在于:二者处于运行时错误的处理方式。

  • 调用redis.call()函数产生的错误将直接返回到执行它的客户端
  • 调用redis.pcall()函数时遇到的错误将返回到脚本的执行上下文中,以进行可能的处理
> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
OK

上面的脚本接收2个参数,Key值、Value值。脚本的执行效果跟 set foo bar 直接调用命令行一致

脚本缓存

在之前的示例中,都是通过调用EVAL命令运行脚本。假设脚本逻辑复杂导致源代码很多。重复调动EVAL来执行相同的脚本,会造成网络带宽浪费。

由此,Redis为脚本提供了一种缓存机制,该方式类似数据库中的存储过程,先将复杂的逻辑通过函数的方式固定到服务器,然后通过函数名 + 参数 指定动态逻辑。

具体的实现是调用script LOAD命令并提供其源代码,将脚本加载到服务器的缓存中。服务器不执行脚本,而是只编译脚本并将其加载到服务器的缓存中。加载后,可以使用从服务器返回的SHA1摘要执行缓存脚本。

redis> SCRIPT LOAD "return 'Immabe a cached script'"
"c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f"
redis> EVALSHA c664a3bf70bd1d45c4284ffebb65a6f2299bfc9f 0
"Immabe a cached script"

Redis脚本缓存是不稳定的。它不被视为数据库的一部分,也不被持久化。当服务器重新启动时、复制副本承担主角色时的故障切换期间,或由SCRIPT FLUSH明确清除缓存。这意味着缓存的脚本是短暂的,缓存的内容随时可能丢失。

使用脚本的应用程序应始终调用EVALSHA来执行脚本。如果脚本的SHA1摘要不在缓存中,服务器将返回错误。例如:

redis> EVALSHA ffffffffffffffffffffffffffffffffffffffff 0
(error) NOSCRIPT No matching script

在Pipeline请求中执行EVALSHA函数需要特别注意,pipeline中请求的命令按发送顺序运行,但其他客户端的命令可能会在这些命令之间交错执行。因此,NOSCRIPT错误可能从流水线请求返回,但无法处理。因此,客户端库在pipeline请求中应使用EVAL命令执行lua脚本。

脚本维护

Redis 服务器提供了几个命令对lua脚本进行维护:

  • SCRIPT FLUSH - 该命令会强制刷新(删除)Redis服务中的所有脚本信息
  • SCRIPT EXISTS - 给定一个或多个SHA1作为参数,判断脚本是否存在。返回1 即存在;0 不存在
  • SCRIPT LOAD script - 之前用到过 在Redis服务端注册缓存指定脚本
  • SCRIPT KILL - 该命令是中断长时间运行的脚本(也称为慢脚本)的唯一方法,而不是关闭服务器。一旦脚本的执行持续时间超过配置的最大执行时间阈值,则该脚本被视为缓慢。SCRIPT KILL命令只能用于在执行过程中未修改数据集的脚本(因为停止只读脚本不会违反脚本引擎保证的原子性)。
  • SCRIPT DEBUG

Lua 脚本DEBUG

测试脚本

-- 创建 script.lua 文件 内容如下
local pong = redis.call('ping')
local data = 'world'
redis.debug('hello',data)
redis.log(redis.LOG_WARNING, "foo bar")
return pong
# 验证脚本是否能正常运行
AndydeMacBook-Pro:tmp andy$ redis-cli --eval script.lua 
PONG

启动Debug

# 执行脚本,进入debug模式 如图所示
redis-cli --ldb --eval script.lua

在这里插入图片描述

进入Debug模式后,可以相关帮助信息

  • quit - 退出debug模式
  • restart - 重新以debug模式执行脚本
  • help - 查看帮助文档

测试指令

lua debugger> help
Redis Lua debugger help:
[h]elp               Show this help.
[s]tep               Run current line and stop again. (执行下一步)
[n]ext               Alias for step. (执行下一步)
[c]continue          Run till next breakpoint. 
[l]list              List source code around current line. 输出源代码信息
[l]list [line]       List source code around [line].
                     line = 0 means: current position.
[l]list [line] [ctx] In this form [ctx] specifies how many lines
                     to show before/after [line].
[w]hole              List all source code. Alias for 'list 1 1000000'. 输出全部源代码
[p]rint              Show all the local variables. 打印变量
[p]rint <var>        Show the value of the specified variable.
                     Can also show global vars KEYS and ARGV.
[b]reak              Show all breakpoints.  给所有代码打断点
[b]reak <line>       Add a breakpoint to the specified line. 给指定行号打断点信息
[b]reak -<line>      Remove breakpoint from the specified line.
[b]reak 0            Remove all breakpoints. 删除断点
[t]race              Show a backtrace.
[e]eval <code>       Execute some Lua code (in a different callframe). 执行lua代码
[r]edis <cmd>        Execute a Redis command.  执行redis执行
[m]axlen [len]       Trim logged Redis replies and Lua var dumps to len.
                     Specifying zero as <len> means unlimited.
[a]abort             Stop the execution of the script. In sync
                     mode dataset changes will be retained.

Debugger functions you can call from Lua scripts:
redis.debug()        Produce logs in the debugger console.
redis.breakpoint()   Stop execution as if there was a breakpoint in the
                     next line of code.

Debug 之旅

新增断点

在这里插入图片描述

顺序执行

输入n 敲回车键

在这里插入图片描述

打印变量

lua debugger> print pong
<value> {["ok"]="PONG"}

Debug 日志

执行到第三步时 会在debug 控制台输出 信息 如下

lua debugger> n
<debug> line 3: "hello", "world"
* Stopped at 4, stop reason = break point
->#4   redis.log(redis.LOG_WARNING, "foo bar")

服务端日志

接着一步步执行,直至Debug完毕即可,需要注意的是,在示例中 第四行 会在Redis 服务端打印日志。

总结

使用Redis Lua脚本最大的优势是业务代码原子执行,Redis 服务能保证Lua脚本中的操作要么全部成功,要么全部失败,由此来弥补Redis 多个指令之间不能原子执行的问题。基于这个特性,通常使用Lua脚本来实现分布式锁、秒杀等业务场景。

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

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

相关文章

【20天快速掌握Python】day02-数据类型转换及运算符

1、数据类型转换 函数说明int(x [,base ])将x转换为一个整数float(x)将x转换为一个浮点数str(x)将对象 x 转换为字符串bool(x)将对象x转换成为布尔值转换成为整数 print(int("123")) # 123 将字符串转换成为整数 print(int(123.78)) # 123 将浮点数转换成为整数 …

腾讯云存储产品全线升级,满足更多高性能存储场景

数字经济时代&#xff0c;诞生了海量数据资源&#xff0c;促使数据存储技术也在不断推陈出新。12月1日&#xff0c;在2022腾讯全球数字生态大会存储专场上&#xff0c;腾讯云发布了多款云存储产品能力上新&#xff0c;并对分布式存储、高性能存储、日志大数据、云原生数据湖等产…

CMSIS hal库 标准库 pack(芯片支持包)

ARM Cortex™ 微控制器软件接口标准(CMSIS&#xff1a;Cortex Microcontroller Software Interface Standard) 是 Cortex-M 处理器系列的与供应商无关的硬件抽象层 CMSIS英文全称Common Microcontroller Software Interface Standard&#xff0c;☞通用微控制器软件接口标准&a…

OAuth2.0介绍

1. OAuth2.0介绍 OAuth&#xff08;开放授权&#xff09;是一个开放标准&#xff0c;允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。OAuth2.0是OAuth协议的延续版本&#xff0…

【蓝桥杯选拔赛真题51】Scratch赛车训练 少儿编程scratch图形化编程 蓝桥杯选拔赛真题讲解

目录 scratch赛车训练 一、题目要求 编程实现 二、案例分析 1、角色分析

python解决 某文库禁用文段批量下载 并保存到文档

嗨害大家好鸭&#xff01; 我是小熊猫鸭~ 大家是不是在写毕业论文的时候 需要参考某一段的内容 要用到复制粘贴&#xff0c;但是吧&#xff0c;某文库就需要付费&#xff0c; 就老难受了… 我们今天就来解决这个"老难受" 源码、资料点击此处 环境使用&#xff1…

项目实战案例丨教辅机构信息化平台跟着这个做

一. 基本简介 最近正值计算机专业的小伙伴忙着整理毕业设计&#xff0c;有不少童靴问辉哥&#xff0c;有没有合适的项目作为毕业设计项目。恰好辉哥这里就有一个适合作为毕设的项目&#xff0c;那么辉哥就写一篇文章&#xff0c;聊聊这个项目&#xff0c;希望可以对有需要的你…

照片怎么制作动态照片?这篇文章教会你如何制作

大家不知道有没有在网上刷到过一些本来是静态的照片&#xff0c;可照片里的局部却能够动起来的动态图片&#xff0c;我看完后觉得这种特效很神奇&#xff0c;既有趣又不会有违和感。那你想知道动态照片怎么制作吗&#xff1f;今天我就来给大家介绍一下制作动态图片的具体方法&a…

基于JWT用户认证分析

在前后端分离开发时为什么需要用户认证呢&#xff1f;原因是由于HTTP协定是不储存状态的(stateless)&#xff0c;这意味着当我们透过帐号密码验证一个使用者时&#xff0c;当下一个request请求时它就把刚刚的资料忘了。 于是我们的程序就不知道谁是谁&#xff0c;就要再验证一…

Spring Security 认证授权(一)

1.基本概念1.1.什么是认证 进入移动互联网时代&#xff0c;大家每天都在刷手机&#xff0c;常用的软件有微信、支付宝、头条等&#xff0c;下边拿微信来举例子说明认证相关的基本概念&#xff0c;在初次使用微信前需要注册成为微信用户&#xff0c;然后输入账号和密码即可登录微…

大二毕设.1-学生信息管理系统

目录 技术选型: 功能概括: 可扩展性良好&#xff0c;添加其余操作无非是多加点信息&#xff0c;重复编码改数据罢 版本: 基本演示 功能实现讲解 登录校验 可调整每页条数的分页显示与增删查改 不会造成偷窃的部分web代码 技术选型: 前端: Vue Element UI后端: Spring…

喜报|众享链网荣获第二届中国可信区块链安全攻防大赛优秀案例奖

近日&#xff0c;第二届中国可信区块链安全攻防大赛决赛在成都成功举办并圆满落幕。经过预赛初审、预赛复审的层层选拔&#xff0c;众享链网脱颖而出&#xff0c;成功进入赛道三“原创自主区块链平台优秀应用案例评选比赛”总决赛环节&#xff0c;荣获优秀案例奖&#xff0c;入…

[附源码]计算机毕业设计的桌游信息管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

弗洛伊德算法(Floyd)的实现与可视化其最短路径

弗洛伊德算法Floyd是针对多源路径找出最短的路径&#xff0c;其中数据结构会使用到前面介绍过的邻接矩阵&#xff0c;有兴趣的可以先查阅&#xff1a;图数据结构之邻接矩阵Adjacency Matrix(Python版) 先了解这个邻接矩阵然后再回看本文章也可以。 区别在于这里我们介绍的是带…

浅撸一下spring源码---大致内容实现

手写spring-模拟spring 1&#xff0c;普及一个小知识 UserService.class Component public class UserService{public void test(){ System.out.println("test") }}Test.classpublic class Test{public static void main(String[] args){AnnotationConfigApplicati…

什么软件可以将录音转写为文字?这几款好用软件不容错过

录音实时转写软件有哪些 &#xff08;百&#xff09;录音实时转写软件有哪些&#xff1f;这些录音转文字软件推荐给你 &#xff08;搜&#xff09;音频转文字工具有哪些&#xff1f;推荐三个实用转写软件 &#xff08;企&#xff09;哪些软件可以把录音转写为文字&#xff1f;这…

微信小程序|系统配送员如何登陆抢单?同城配送、预约服务

系统中有多个功能有有配送端&#xff0c;最主要的是同城配送&#xff0c;和预约服务两个功能&#xff0c;首先介绍一下同城配送的配送员登录&#xff08;扩展的同城配送需要开启&#xff09; 第一步&#xff0c;设置模板消息&#xff0c;配送员通过微信模板消息接收配送信息&am…

离婚数据可视化,经济越发达的地区离婚率越高,但为何天津离婚率最高?

这几年我国的离婚率持续走高&#xff0c;2021年全国各个省份平均离婚率在2.1‰&#xff0c;离婚率高于和低于全国平均水平的省份各有15个。 离婚率高于平均水平2.1‰有9个是北方地区&#xff0c;分别是天津、北京、新疆和内蒙古以及黑吉辽三省&#xff1b;南方地区有6个省份高…

[附源码]Python计算机毕业设计电视设备租借系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

最全的Go资料汇总和最走心的学Go建议

推荐语 最用心的Go学习资料和学习建议&#xff0c;可能没有之一。怎么学Go快&#xff1f;有哪些教程建议看&#xff1f;学到什么程度能去找工作&#xff1f;我觉得这个问题的关键要看你的目标是什么&#xff1f;一定要结合你自己的情况去考虑这个事情。 前言 最近不少读者私…