Redis中的Lua脚本(三)

news/2024/9/24 2:50:08/

Lua脚本

EVAL命令的实现

EVAL命令的执行过程可以分为以下三个步骤:

  • 1.根据客户端给定的Lua脚本,在Lua环境中定义一个Lua函数
  • 2.将客户端给定的脚本保存到lua_scripts字典,等待将来进一步使用
  • 3.执行刚刚在Lua环境中定义的函数,以此来执行客户端给定的Lua脚本
    以下命令作为示例,分别介绍EVAL命令执行的三个步骤:
127.0.0.1:6379> EVAL "return 'hello world'" 0
"hello world"

定义脚本函数

当客户端向服务器发送EVAL命令,要求执行某个Lua脚本的时候,服务器首先要做的就是在Lua环境中,为传入的脚本定义一个与这个脚本相对应的Lua函数,其中,Lua函数的名字由f_前缀加上脚本的SHA1校验和(四十个字符长)组成,而函数的体(body)则是脚本本身

使用函数来保存客户端传入的脚本有以下好处:

  • 1.执行脚本的步骤非常简单,只要调用与脚本相对应的函数即可
  • 2.通过函数的局部性来让Lua环境保持清洁,减少了垃圾回收的工作量,并且避免了使用全局变量
  • 3.如果某个脚本所对应的函数在Lua环境中被定义过至少一次,那么只要记得这个脚本的SHA1校验和,服务器就可以在不知道脚本本身的情况下,直接通过调用Lua函数来执行脚本,这时EVALSHA命令的实现原理
例子
  • 举个例子,对于命令:
EVAL "return 'hello world'" 0

来说,服务器将在Lua环境中定义以下函数:

function f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91()
return 'hello world'
end

因为客户端传入的脚本为return ‘hello world’,而这个脚本的SHA1校验和为5332031c6b470dc5a0dd9b4bf2030dea6d65de91所以函数的名字为f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91,而函数的体则为return ‘hello world’.

lua_scripts_31">将脚本保存到lua_scripts字典

EVAL命令要做的第二件事是将客户端传入的脚本保存到服务器lua_scripts字典里面。
在这里插入图片描述

例子
  • 举个例子,对于命令:
EVAL "return 'hello world'" 0

来说,服务器将在lua_scripts字典中新添加一个键值对,其中键为Lua脚本的SHA1校验和

5332031c6b470dc5a0dd9b4bf2030dea6d65de91

而值则为Lua脚本本身:

retuern 'hello world'

添加新键值对之后,lua_scripts字典如上图所示:

执行脚本函数

在为脚本定义函数,并且将脚本保存到lua_scripts字典之后,服务器还需要进行一些设置钩子、传入参数之类的准备动作,才能正式开始执行脚本。整个准备和执行脚本的过程如下:

  • 1.将EVAL命令中传入的键名(key name)参数和脚本参数分别保存到KEYS数组和ARGV数组,然后将这两个数组作为全局变量传入到Lua环境里面
  • 2.为Lua环境装载超时处理钩子(hook),这个钩子可以在脚本出现超时运行情况是,让客户端通过SCRIPT KILL命令停止脚本,或者通过SHUTDOWN命令直接关闭服务器
  • 3.执行脚本函数
  • 4.移除之前装载的超时钩子
  • 5.将执行脚本函数所得的结果保存到客户端状态的输出缓冲区里面,等待服务器将结果返回给客户端
例子
  • 举个例子。对于如下命令:
EVAL "return 'hello world'" 0

服务器将执行以下动作:
1.因为这个脚本没有给定任何键名参数或者脚本参数,所以服务器会跳过传值到KEYS数组或ARGV数组这一步
2.为Lua胡娜经装载超时处理钩子
3.在Lua环境中执行f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91函数
4.移除超时钩子
5.将执行f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91函数所得的结果"hello world"保存到客户端状态的输出缓冲区里面
6.对Lua环境执行垃圾回收操作
至此,命令:

EVAL "return 'hello world'" 0

执行算是完成了,之后服务器只要将保存在输出缓冲区里面的执行结果返回给执行EVAL命令的客户端就可以了

EVALSHA命令的实现

每个被EVAL命令成功执行过的Lua脚本,在Lua环境里面都有一个与这个脚本相对应的Lua函数,函数的名字由f_前缀加上40个字符串的SHA1校验和组成,例如f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91.只要脚本对应的函数曾经在Lua环境里面定义过,那么即使不知道脚本的内容本身,客户端也可以根据脚本的SHA1校验和来调用脚本对应的函数,从而达到执行脚本的目的,这就是EVALSHA命令的实现原理。

伪代码描述

def EVALSHA(sha1):
# 拼接出函数的名字
# 例如 f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91
func_name = "f_" + sha1# 查看这个函数在Lua环境中是否存在
if function_exists_in_lua_env(func_name):
# 如果函数存在,那么执行它
execute_lua_function(func_name)
else:
# 如果函数不存在,那么返回一个错误
send_scirpt_error("SCRIPT NOT FOUND")

例子

  • 举个例子。当服务器执行完以下EVAL命令之后:
127.0.0.1:6379> EVAL "return 'hello world'" 0
"hello world"

Lua环境里面就定义了以下函数:

function f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91()
return 'hello world'
end

当客户端执行以下EVALSHA命令时:

127.0.0.1:6379> EVALSHA 5332031c6b470dc5a0dd9b4bf2030dea6d65de91 0
"hello world"

服务器首先根据客户端输入的SHA1校验和,检查函数f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91
是否存在于Lua环境中,得到的回应时该函数确实存在,于是服务器执行Lua环境中的f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91函数,并将结果"hello world"返回给客户端


http://www.ppmy.cn/news/1429141.html

相关文章

TCP协议学习记录

TCP协议学习记录 简述 对TCP有诸多疑惑的地方: 1、TCP和socket的关系 2、TCP客户端和服务端如何区分 3、TCP连接的两端,端口号需要一致吗 什么是socket 一种编程抽象 编写程序时,利用socket可以使用TCP;假设现在已经将TCP协议…

密码学 | 数字证书:应用

🥑原文:数字签名和数字证书的原理解读 - 知乎 🥑前文:密码学 | 数字签名 数字证书 - CSDN 🥑提示:把客户端想成 Alice,服务器端想成 Bob 即可。客户端实际上指的是客户端浏览器。 下面&#…

Navicat Premium 16最新版激活 mac/win

Navicat Premium 16 for Mac是一款专业的多连接数据库管理工具。它支持连接多种类型的数据库,包括MySQL、MongoDB、Oracle、SQLite、SQL Server、PostgreSQL等,可以同时连接多种数据库,帮助用户轻松地管理和迁移数据。 Navicat Premium 16 fo…

【Linux】学习记录_14_线程

14 线程 14.1 线程和进程 进程是资源管理的最小单位,每个进程都有数据段、代码段和堆栈段,进程切换时都有复杂的上下文切换等动作。进程切换上下文时, 需要重新映射虚拟地址空间、进出OS内核、寄存器切换,还会干扰处理器的缓存机…

ZooKeeper监听器原理

ZooKeeper监听器原理 ZooKeeper 监听器(Watcher)是 ZooKeeper 提供的一种机制,用于实现分布式系统中的事件通知。 1.流程 注册监听器: 客户端在与 ZooKeeper 服务器建立连接后,可以通过某些操作(例如获…

lua整合redis

文章目录 lua基础只适合lua连接操作redis1.下载lua依赖2.导包,连接3.常用的命令1.set,get,push命令 2.自增管道命令命令集合4.使用redis操作lua1.实现秒杀功能synchronized关键字 分布式锁 lua 基础只适合 1.编译 -- 编译 luac a.lua -- 运行 lua a.lua2.命名规范 -- 多行注…

数据结构--双向链表

在讲双向链表之前,我们先了解一下链表的分类: 链表的结构⾮常多样,主要分为带头与不带头、单向与双向、循环与不循环。三个种类可以任意搭配,所以总共可以形成八种链表,但是最常用的是单向不带头不循环链表和双向带头循…

设计模式- 代理模式(Proxy Pattern)结构|原理|优缺点|场景|示例

目录 设计模式(分类) 设计模式(六大原则) 创建型 工厂方法 抽象工厂模式 单例模式 建造者模式 原型模式 结构型 适配器模式 装饰器模式 代理模式 代理模式(Prox…