Redis中的Lua脚本(一)

Lua脚本

概述

Redis从2.6版本开始引入对Lua脚本的支持,通过在服务器中嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务器端原子地执行多个Redis命令。其中使用EVAL命令可以直接对输入的脚本进行求值:

127.0.0.1:6379> EVAL "return 'hello world'" 0
"hello world"

而使用EVALSHA命令则可以根据脚本的SHA1校验和来对脚本进行求值,但这个命令要求校验和对应的脚本必须至少被EVAL命令执行过
一次:

127.0.0.1:6379> EVAL "return 1+1" 0
(integer) 2
127.0.0.1:6379> EVALSHA "a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9" 0 // 上一个脚本的校验和
(integer) 2

或者这个校验和对应的脚本曾经被SCRIPT LOAD命令载入过:

127.0.0.1:6379> SCRIPT Load "return 2*2"
"4475bfb5919b5ad16424cb50f74d4724ae833e72"
127.0.0.1:6379> EVALSHA "4475bfb5919b5ad16424cb50f74d4724ae833e72" 0
(integer) 4

创建并修改Lua环境

为了在Redis服务器中执行Lua脚本,Redis在服务器内嵌了一个Lua环境(evnironment),并对这个Lua环境进行了一系列修改,从而确保这个Lua环境可以满足Redis服务器的需要。Redis服务器创建并修改Lua环境的整个过程由以下步骤组成:

  • 1.创建一个基础的Lua环境,之后的所有修改都是针对这个环境进行的。
  • 2.载入多个函数库到Lua环境里面,让Lua脚本可以使用这些函数库来进行数操作
  • 3.创建全局表格redis,这个表格包含了对Redis进行操作的函数,比如用于在Lua脚本中执行Redis命令的redis.call函数
  • 4.使用Redis自制的随机函数来替换Lua原有的带有副作用的随机函数,从而避免在脚本中引入副作用
  • 5.创建排序辅助函数,Lua环境使用这个辅佐函数来对一部分Redis命令的结果进行排序,从而消除这些命令的不确定性
  • 6.创建redis.pcall函数的错误报告辅助函数,这个函数可以提供更详细的出错信息
  • 7.对Lua环境中的全局环境进行保护,防止用户在执行Lua脚本的过程中,将额外的全局变量添加到Lua环境中
  • 8.将完成修改的Lua环境保存到服务器状态的Lua环境中,等待执行服务器传来的Lua脚本

创建Lua环境

服务器首先调用Lua的C API函数lua_open,创建一个新的Lua环境。因为lua_open函数创建的只是一个基本的Lua环境,为了让这个Lua环境可以满足Redis的操作要求,接下来服务器将对这个Lua环境进行一系列修改。

载入函数库

Redis修改Lua环境的第一步,就是将以下函数库载入到Lua环境里面:

  • 1.基础库(base library):这个库包含Lua的核心(core)函数,比如assert、error、pairs、tostring、pcall等。另外,为了防止用户从外部文件中引入不安全的代码,库中的loadfile函数会被删除
  • 2.表格库(table library):这个库包含用于处理表格的通用函数。比如table.concat、table.insert、table.remove、table.sort等
  • 3.字符串库(string library):这个库包含用于处理字符串的通用函数,比如用于对字符串进行查找的string.find函数,对字符串进行格式化的string.format函数,查看字符串长度的string.len函数,对字符串进行反转的string.reverse函数等
  • 4.数据库(math libraray):这个库是标准C语言数据库的结构,它包括计算绝对值的math.abs函数,返回多个数中的最大值和最小值的math.max函数和math.min函数,计算二次方根的math.sqrt函数,计算对数的math.log函数等
  • 5.调试库(debug libraray):这个库提供了对程序进行调试所需的函数,比如对程序设置钩子和取得钩子的debug.sethook函数和debug.gethook函数,返回给定函数相关信息的debug.getinfo函数,为对象设置元数据的debug.setmetatable函数,获取对象元数据的debug.getmetatable函数等
  • 6.Lua CJSON库:这个库用于处理UTF-8编码的JSON格式,其中cjson.decode函数将一个JSON格式的字符串转换为一个Lua值,
    而cjson.encode函数将一个Lua值序列化为JSON格式的字符串
  • 7.Struct库:这个库用于在Lua值和C结构(struct)之间进行转换,函数struct.pack将多个Lua值打包成一个类结构(struct-like)字符串,而函数struct.unpack则从一个类结构字符串中解包出多个Lua值
  • 8.Lua cmsgpack库:这个库用于处理MessagePack格式的数据,其中cmsgpack.pack函数将Lua值转换为MessagePack数据,而cmsgpack.unpack函数则将messagepack数据转换为Lua值通过使用这些功能强大的函数库,Lua脚本可以直接对执行Redis命令获得的数据进行复杂的操作

创建Redis全局

服务器将在Lua环境中创建一个redis表格(table),并将它设置为全局变量,这个redis表格包含以下函数:

  • 1.用于执行Redis命令的redis.call和redis.pcall函数
  • 2.用于记录Redis日志(log)的redis.log函数,以及相应的日志级别(level)常量:redis.LOG_DEBUG,redis.LOG_VERBOSE,redis.LOG_NOTICE以及redis.LOG_WARNING
  • 3.用于计算SHA1校验和的redis.sha1hex函数
  • 4.用于返回错误信息的redis.error_reply函数和redis.status_reply函数。
    在这些函数里面,最常用也最重要的要数redis.call函数和redis.pcall函数,通过这两个函数,用户可以直接在Lua脚本中执行Redis命令:
127.0.0.1:6379> EVAL "return redis.call('ping')" 0
PONG

使用Redis自制的随机函数来替换Lua原有的随机函数

为了保证相同的脚本可以在不同的机器上产生相同的结果,Redis要求所有传入服务器的Lua脚本,以及Lua环境中的所有函数,都必须是无副作用(side effect)的纯函数(pure function).但是,在之前载入Lua环境的match函数库中,用于生成随机数的math.random函数和math.randomseed函数都是带有副作用的,它们不符合Redis对Lua环境的无副作用要求。因为这个原因,Redis使用自制的函数替换了math库中原有的math.random函数和math.randomseed函数,替换之后的两个函数有以下特征:

  • 1.对于相同的seed来说,math.random总产生相同的随机数绪列,这个函数是一个纯函数
  • 2.除非在脚本中使用math.randomseed显示地修改seed,否则每次运行脚本时,Lua环境都使用固定地math.randomseed(0)语句来初始化seed
例子
  • 举个例子。使用以下脚本,我们可以打印seed值为0时,math.random对于输入10至1所产生地随机绪列
--random-with-default-seed.lualocal i = 10
local seq ={}
while (i > 0) do
seq[i] = math.random(i)
i = i+1
endreturn seq

无论执行这个脚本多少次产生的值都是相同的

E:\redis>redis-cli --eval test.lua
1) (integer) 1
2) (integer) 2
3) (integer) 2
4) (integer) 3
5) (integer) 4
6) (integer) 4
7) (integer) 7
8) (integer) 1
9) (integer) 7
10) (integer) 2

但是如果我们在另一个脚本里面调用math.randomseed将seed修改为10086

--random-with-default-seed.luamath.randomseed(10086) -- change seed
local i = 10
local seq ={}
while (i > 0) do
seq[i] = math.random(i)
i = i-1
endreturn seq

那么这个脚本生成的随机数绪列将和使用默认seed值0时生成的随机绪列不同:

E:\redis>redis-cli --eval test1.lua
1) (integer) 1
2) (integer) 1
3) (integer) 2
4) (integer) 1
5) (integer) 1
6) (integer) 3
7) (integer) 1
8) (integer) 1
9) (integer) 3
10) (integer) 1

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

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

相关文章

【Linux】git

大家好,我是苏貝,本篇博客带大家了解Linux的编译器-gcc/g,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 1.安装git2.在gitee上创建仓库3.首次配置4.下载仓库到本地5.三板斧6.git log7.gi…

待研究技术

Fabric.js H5 Canvas的js库 Fabric.js是一个用于创建交互式的HTML5 Canvas应用程序的JavaScript库。它提供了一个简单而强大的API,用于在Web浏览器中绘制和操作图形对象。Fabric.js可以用于创建各种图形应用程序,例如绘图编辑器、图像编辑器、流程图、地…

JavaSE-13笔记【集合2(+2024新)】

文章目录 3.Map3.1 Map继承结构3.2 Map接口的常用方法3.3 遍历Map3.4 HashMap集合3.4.1 HashMap集合key的特点3.4.2 HashMap集合的key存储自定义类型3.4.3 哈希表3.4.3.1 哈希表的介绍3.4.3.2 哈希表的存储原理 3.4.4 存放在HashMap和HashSet集合key部分的元素必须同时重写hash…

2024年在Vim中开发vue2+java

neovim 0.5刚出来的时代,那时刚有lua插件我很狂热。每天沉迷于打造自己的IDE之中。写过一堆相关的博客,也录过一些视频教程。后来发现neovim的接口和插件更新的很快,导致配置文件要不定期的修改,才能保证新版本的插件的适配。我也…

理解思维链Chain of Thought(CoT)

Chain of Thought(CoT),即“思维链”,是人工智能领域中的一个概念,特别是在自然语言处理和推理任务中。它指的是一种推理过程,其中模型在生成最终答案之前,先逐步推导出一系列的中间步骤或子目标…

部署Zabbix5.0

一.部署zabbix客户端 端口号10050 zabbix 5.0 版本采用 golang 语言开发的新版本客户端 agent2 。 zabbix 服务端 zabbix_server 默认使用 10051 端口,客户端 zabbix_agent2 默认使用 10050 端口。 1.1.关闭防火墙和selinux安全模块 systemctl disable --now fir…

json diff patch

文件和图片的比对靠字符串 目录 流程 安装 效果 使用 自适应 数组:最长公共子序列(LCS) 数组中的对象,给定id,类似dom tree的比较 流程 安装 npm install jsondiffpatch import * as jsondiffpatch from jsondiffpatch; const jsond…

Vue3(六):Vue3其他API、Vue3新组件Teleport、Vue2和3区别

一、其他API 1.shallowRef 与 shallowReactive (1)shallowRef 1. 作用:创建一个响应式数据,但只对顶层属性进行响应式处理。 2.用法: let myVar shallowRef(initialValue); 3. 特点:只跟踪引用值的变化&…

IntelliJ IDEA配置类注释模板和方法注释模板

配置类注释模板和方法注释模板 IDEA模板预定义变量类注释模方法注释模板方法参数优化 IDEA模板 在IDEA中,自带的注释模板可能不满足自身需求或者不满意,此时可以通过配置IDEA模板来解决。 预定义变量 内置模板是可编辑的,除了静态文本、代码和…

react中关于类式组件和函数组件对props、state、ref的使用

文章中有很多蓝色字体为扩展链接&#xff0c;可以补充查看。 常用命令使用规则 组件编写方式: 1.函数式 function MyButton() { //直接return 标签体return (<>……</>); }2.类 class MyButton extends React.Component { //在render方法中&#xff0c;return…

GPT-3.5和GPT-Plus的区别

GPT-3.5和GPT-Plus都是OpenAI开发的大型语言模型,但它们之间有一些区别: GPT-3.5就是大家熟知的ChatGPT GPT-Plus 是Open AI 的更强的AI模型GPT-4版本。两者区别是&#xff1a; 模型规模:GPT-Plus是GPT-3的一个更大版本,参数量更多。而GPT-3.5是GPT-3的一个优化版本,在参数量…

基于Copula函数的风光功率联合场景生成_任意修改生成的场景数目(附带Matlab代码)

基于Copula函数的风光功率联合场景生成 削减为6个场景 部分展示削减为5个场景 部分展示 风光等可再生能源出力的不确定性和相关性给系统的设计带来了极大的复杂性&#xff0c;若忽略这些因素&#xff0c;势必会在系统规划阶段引入次优决策风险。因此&#xff0c;在确定系统最佳…

TR-DPO:革新大模型对齐技术

这篇论文中提出的TR-DPO&#xff08;Trust Region Direct Preference Optimization&#xff09;方法的架构或流程设计主要侧重于改进语言模型对齐过程中的稳定性和有效性。 在传统的对齐方法中&#xff0c;模型在学习的时候需要尽可能地靠近一个预先设定的参考模型。这就像是给…

c语言,单链表的实现----------有全代码!!!!

1.单链表的定义和结构 单链表是一种链式的数据结构&#xff0c;它用一组不连续的储存单元存反线性表中的数据元素。链表中的数据是以节点的形式来表示的&#xff0c;节点和节点之间相互连接 一般来说节点有两部分组成 1.数据域 &#xff1a;数据域用来存储各种类型的数据&…

Windows系统下查看C语言文件反汇编

一、配置编译器环境变量 1.下载mingw64 MinGW 的全称是&#xff1a;Minimalist GNU on Windows &#xff0c;MinGW 就是 GCC 的 Windows 版本 。 MinGW-w64 与 MinGW 的区别在于 MinGW 只能编译生成32位可执行程序&#xff0c;而 MinGW-w64 则可以编译生成 64位 或 32位 可执行…

day11 | 栈与队列 part-3 (Go) | 239 滑动窗口最大值、347 前 K 个高频元素 (好难)

今日任务 239 滑动窗口最大值 (题目:. - 力扣&#xff08;LeetCode&#xff09; )347 前 K 个高频元素 (题目: . - 力扣&#xff08;LeetCode&#xff09; )栈与队列总结 239 滑动窗口最大值 题目:. - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 nums&#xf…

处理json文件,并将数据汇总至Excel表格

从scores.jason文件中读取学生信息,输出学生的学号&#xff0c;姓名&#xff0c;各科成绩&#xff0c;平均分, 各科标准差 scores.jason {"学院": "计算机学院","班级": "2022级1班","成绩": [{"学号": 1001,&q…

使用avx2 指令集加速向量算法运算

使用cpu-z 查看cpu指令集 2 向量加&#xff0c;乘法&#xff0c;除法 我们使用向量加&#xff0c;为什么函数是0 到 8 的计算&#xff0c;因为avx2 寄存器为256位&#xff0c;同时设置启动增强指令集 #include <immintrin.h> // 引入包含AVX2指令集的头文件void vecto…

C++类和对象:赋值重载,const成员

文章目录 1.赋值运算符重载1.1运算符重载1.2 赋值运算符重载1.3 前置和后置重载 2.日期类的实现3. const成员函数4 取地址及const取地址操作符重载 上文介绍了前三个默认成员函数&#xff0c;本文会介绍剩下三个&#xff0c; 赋值重载会重点展开。 1.赋值运算符重载 1.1运算符…

代码随想录 Day17 字符串 | LC344 反转字符串 LC541 反转字符串II 卡码网54替换数字

一、反转字符串 题目&#xff1a; 力扣344&#xff1a;反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题…