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

Redis Lua脚本

文章目录

      • 一.引言
      • 二.eval简介
      • 三.lua数据类型和redis数据类型之间转换
      • 四.脚本的原子性
      • 五.错误处理
      • 六.纯函数脚本
      • 七.选择内部脚本

一.引言

eval和evalsha命令使用内置的lua解释器,可以对lua脚本进行求值。

二.eval简介

  • 第一个参数是一段脚本程序
  • 第二个参数是参数的个数,后面的参数表示脚本中所用到的那些redis键,这些键名参数可以在lua中通过全局变量KEYS数据,以1为基址的形式访问(KEYS[1],KEYS[2]…)。
  • 那些不是键名的附加参数,ARGV[],可以在lua中通过全局变量ARGV数组访问,访问的形式和KEYS变量类似(ARGV[1],ARGV[2]…)

注意:eval命令所有键都应该由KEYS数组来传递,因为不仅仅是eval命令,所有的redis命令在执行之前都会被分析,借此来确定命令会对哪些键进行操作。对于eval命令来说,必须使用正确的形式来传递键,才能确保分析工作正确地执行。而且可以确保redis集群可以将你的请求发送到正确的集群节点。

例如:

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1]}" 1 foo bar
1) "foo"
2) "bar"

返回结果是redis multi bulk replies的lua数组,这是一个redis的返回类型,您的客户端可能会将他们转换成数组类型

lua脚本中使用lua函数调用redis命令的例子:

  • redis.call()
  • redis.pcall()

两种方式的区别:当reis命令执行结果返回错误是,redis.call()将返回给调用者一个错误,而redis.pcall()会将捕获的错误以lua表的形式返回。

三.lua数据类型和redis数据类型之间转换

当lua通过call()或pcall()函数执行redis命令的时候,命令的返回值会被转换成lua数据结构。同样地,当lua脚本在redis内置的解释器里运行时,lua脚本的返回值也会被转换成reids协议,然后由eval将值返回给客户端。

数据类型转换之间遵循这样一个设计原则:将一个redis值转换成lua值,之后再将转换所得的lua值转换回redis值,那么这个转换所得的redis值应该和最初的redis值一样。

redis->lua:

  • redis integer reply -> lua number
  • redis bulk reply -> lua string
  • redis multi bulk reply -> lua table
  • redis status reply -> lua table with a single err field containing the error
  • redis error reply -> lua table with a single err field containing the error
  • redis nil reply and nil multi bulk reply -> lua false boolean type

lua->redis:

  • lua number -> redis integer reply
  • lua string -> redis bulk reply
  • lua table -> redis multi bulk reply
  • lua table with a single ok field -> redis status reply
  • lua table with a single err field -> redis error reply
  • lua boolean false -> redis nil bulk reply

特殊lua->redis转换:

  • redis boolean true -> redis integer reply with value of 1

注意:

  • lua中整数和浮点数之间没有任何区别。因此,我们如果将lua的数字转换成整数的回复,这样将舍去小数部分。如果想从lua返回一个浮点数,你应该将它视作一个字符串。
  • nil 作为一个回复的结束,后面的值将不会被返回

例子:

> eval "return {1,2,{3,'Hello World!'}}" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 32) "Hello World!"> eval "return redis.call('get','foo')" 0
"bar"> eval "return {1,2,3.3333,'foo',nil,'bar'}" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"

四.脚本的原子性

redis使用单个lua脚本解释器去运行所有脚本,并且redis也播啊这呢个脚本会以原子性的方式执行:当某个脚本正在运行的时候,不会有其他脚本或者redis命令被执行。这和使用MULTI/EXEC包围的事物很类似。在其他客户端看来,脚本的效果只能是不可见或是已完成。要注意慢脚本的问题,一个蜗牛脚本执行是,其他客户端会因为服务器正忙而无法执行命令。

五.错误处理

  • 当redis.call()在执行命令的过程中发生错误时,脚本会停止执行,并返回一个脚本错误

    > del foo
    (integer) 1
    > lpush foo a
    (integer) 1
    > eval "return redis.call('get','foo')" 0
    (error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): ERR Operation against a key holding the wrong kind of value
    
  • 和redis.call()不同,redis.pcall()出错时并不引发错误,而是返回一个带err域的lua表,用于表示错误

    redis 127.0.0.1:6379> EVAL "return redis.pcall('get', 'foo')" 0
    (error) ERR Operation against a key holding the wrong kind of value
    

六.纯函数脚本

脚本应该被写成纯函数脚本。脚本应该具有以下属性:

  • 对于同样的数据集输入,给定相同的参数,脚本的redis写命令总是相同的。脚本执行的操作不能依赖于任何吟唱(非显式)数据,不能依赖于脚本在执行过程中、或在不同执行时间之间可能变更的状态,并且也不能依赖于任何来自IO设备的外部输入。

使用系统时间,调用randomkey那样的随机命令,或者使用lua的随机数生成器,渴死以上的这些操作,都会遭整脚本的求值无法每次都得出同样的结果。为了保证上述脚本的属性,redis做了以下工作:

  • lua没有方位系统时间或者其他内部状态的命令
  • 执行随机命令(randomkey,time)时,redis会返回一个错误,阻止这样的脚本运行
  • lua脚本中调用哪些返回无序元素的命令时,执行命令所得的数据在返回给lua之前会先执行一个静默的字典排序。如调用:redis.call(“smembers”, KEYS[1]) ,返回的总是排过序的元素
  • 对lua的伪随机数生成函数math.random,math.randomseed进行修改,使得每次在运行新脚本的时候总是拥有同样的seed值。者意味着,每次运行脚本是,只要不使用math。randomseed,那么math.random产生的随机数序列总是相同的

为了防止不必要的数据泄漏进lua环境,redis脚本不允许创建全局变量。如果一个脚本需要在多次执行之间维持某种状态,它应该使用reids key来进行状态保存,企图在脚本中访问一个全局变量将引起脚本停止,eval命令会返回一个错误。

七.选择内部脚本

lua脚本之影响脚本本身的执行,但不修改当前客户端调用脚本时选定的数据库。

可用库:

  • base lib

  • table lib

  • string lib

  • math lib

  • debug lib

  • struct lib

    拆装箱处理

    127.0.0.1:6379> eval 'return struct.pack("HH", 1, 2)' 0
    "\x01\x00\x02\x00"
    127.0.0.1:6379> eval 'return {struct.unpack("HH", ARGV[1])}' 0 "\x01\x00\x02\x00"
    1) (integer) 1
    2) (integer) 2
    3) (integer) 5
    127.0.0.1:6379> eval 'return struct.size("HH")' 0
    (integer) 4
    
  • cjson lib

    json处理

    redis 127.0.0.1:6379> eval 'return cjson.encode({["foo"]= "bar"})' 0
    "{\"foo\":\"bar\"}"
    redis 127.0.0.1:6379> eval 'return cjson.decode(ARGV[1])["foo"]' 0 "{\"foo\":\"bar\"}"
    "bar"
    
  • cmsgpack lib

    简单快速的message pack操纵

    127.0.0.1:6379> eval 'return cmsgpack.pack({"foo", "bar", "baz"})' 0
    "\x93\xa3foo\xa3bar\xa3baz"
    127.0.0.1:6379> eval 'return cmsgpack.unpack(ARGV[1])' 0 "\x93\xa3foo\xa3bar\xa3baz"
    1) "foo"
    2) "bar"
    3) "baz"
    
  • bittop lib

    为lua位运算模块增加了按位操作数

    127.0.0.1:6379> eval 'return cmsgpack.pack({"foo", "bar", "baz"})' 0
    "\x93\xa3foo\xa3bar\xa3baz"
    127.0.0.1:6379> eval 'return cmsgpack.unpack(ARGV[1])' 0 "\x93\xa3foo\xa3bar\xa3baz"
    1) "foo"
    2) "bar"
    3) "baz"
    
  • redis.sha1hex function

相关文章:

Redis Lua脚本

文章目录一.引言二.eval简介三.lua数据类型和redis数据类型之间转换四.脚本的原子性五.错误处理六.纯函数脚本七.选择内部脚本一.引言 eval和evalsha命令使用内置的lua解释器,可以对lua脚本进行求值。 二.eval简介 第一个参数是一段脚本程序第二个参数是参数的个…...

web自动化测试-执行 JavaScript 脚本

JavaScript 是一种脚本语言,有的场景需要使用 js 脚本注入辅助我们完成 Selenium 无法做到的事情。 当 webdriver 遇到无法完成的操作时,可以使用 JavaScript 来完成,webdriver 提供了 execute_script() 方法来调用 js 代码。 执行 js 有两种…...

libevent笔记——简单介绍

背景 libevent libevent – an event notification library 官方定义:libevent是一个事件通知的库。更详细的介绍参考官方的就够了,这里我摘抄一下,并做一些注释 The libevent API provides a mechanism to execute a callback function whe…...

C++学习笔记-多态

多态的概念 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态 。 举个例子:比如 买票这个行为 ,当 普通人 买票时,是全价买票&#xff1b…...

5632: 三角形

描述平面坐标系下,给定不共线的三个点组成一个三角形,问三角形最短的边长和最长的边长各为多少?输入输入包含3行,每行两个整数,表示一个点的坐标x和y。输出输出包括2个小数,分别为最短的边长和最长的边长。…...

Java基础--IO操作

一、IO原理及分类 一、IO原理 1、I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输,如读写文件,网络通信等。 2、java程序中对于数据的输入/输出操作一般都是以流的方式进行 3、java.io包下提供各…...

C++多线程

目录一、C线程库1. 认识thread类2. 线程函数的参数3. this_thread二、原子操作三、C互斥锁1. mutex2. lock_guard3. unique_lock四、C条件变量1. condition_variable2. 实现两个线程交替打印奇偶数一、C线程库 1. 认识thread类 在C11之前没有多线程的概念,涉及到的…...

【Arduino使用nRF24L01 】

【Arduino使用nRF24L01 】 1. 概述2. nRF24L01 收发器模块2.1工作原理2.2 NRF24L01模块变体2.3 nRF24L01 模块引脚排列3. 如何将 nRF24L01 连接到 Arduino3.1 原理接线图3.2 Arduino 和 nRF24L01 代码3.3 代码说明4. 故障排除5. 两个NRF24L01和Arduino进行双向无线通信5.1 nRF2…...

Appium自动化测试框架是一种较为优雅的使用方式

以操作小米商城下单为例流程是 启动小米商城app, 点击分类,点击小米手机, 点击小米10 至尊版,点击加入购物车,点击确定....原脚本Copyfrom time import sleep from appium import webdriver from selenium.common.exceptions impo…...

Linux c编程之应用交互协议分析与设计

在实际编程应用中,两个或多个功能服务(模块)之间 需要通过消息交互进行协作完成用户想要的逻辑功能,这里的消息交互指的是应用层的交互。最终数据传输(无论是TCP/IP还是其它)都是以二进制形式完成,但对于应用层协议来说有两种,一种是二进制协议,一种是文本协议。不管是…...

基于YOLOv5的细胞检测实战

数据及代码链接见文末 1.任务与数据集介绍 如下图所示,我们有一个医学细胞数据集,需要从数据集中检测出三种不同的细胞。标签中已经标注了细胞的类别和位置。 我们也可以看到,三种细胞有着不同的形态和颜色,同时数据集的标签也存在没有标注到的细胞 2.数据与标签配置方…...

【经典蓝牙】蓝牙AVRCP协议分析

协议简介 蓝牙AVRCP协议是蓝牙设备之间音视频的控制协议。定义了音频/视频的控制、浏览、查询、通知等一系列的命令集。常用来蓝牙耳机对手机的音乐进行控制,以及获取手机的音乐信息等场景。AVRCP协议有两个角色,分别是controller(CT&#x…...

gin 框架初始教程

一 、gin 入门1. 安装gin :下载并安装 gin包:$ go get -u github.com/gin-gonic/gin2. 将 gin 引入到代码中:import "github.com/gin-gonic/gin"3.初始化项目go mod init gin4.完整代码package mainimport "github.com/gin-go…...

对象分配策略

对象创建后,究竟何去何从,对象在堆中又会经历哪些过程,本篇就会详细解释对象创建后直到对象被回收的整个过程。之前博主已经写过Minor GC、Major GC、Full GC的区别,而本篇也主要根据这几个GC开展。 对象回收过程流程如下图所示: 正常的对象生存过程&a…...

你可能不知道的前端监控方案

前言 现有的大部分监控方案都是针对服务端的,而针对前端的监控很少,诸如线上页面的白屏时间是多少、静态资源的加载情况如何、接口请求耗时好久、什么时候挂掉了、为什么挂掉,这些都不清楚。 因而,我们需要一个前端的页面监控系…...

java spring AOP 完全注解开发

我们先创建一个项目 然后引入java spring aop的依赖 然后 在src下创建目录 我这里 直接就叫 Aop了 下面创建一个User类 参考代码如下 package Aop;import org.springframework.stereotype.Component;Component public class User {public void add(){System.out.println(&qu…...

ctf pwn基础-4

今天是学pwn的第四天,去接触了pwn的整数溢出。 目录 基础 实例讲解 实例讲解2 基础 关于整数溢出,这里以int为例,因为我php之前搞的比较多,以为这个int也是想php一样是64,最大值是9开头的那个,闹了不少笑…...

bool与引用类型

bool与引用类型bool类型介绍与使用bool(布尔类型)大小&#xff1a;1个字节返回值有两个&#xff1a;1(true)&#xff0c;0(false)#include<iostream>using namespace std;int main() {bool a false;bool b true;cout << "a " << a << end…...

tkinter界面的TCP通信/tkinter开启线程接收TCP

前言 用简洁的语言写一个可以与TCP客户端实时通信的界面。之前做了一个项目是要与PLC进行信息交互的界面&#xff0c;在测试的时候就利用TCP客户端来实验&#xff0c;文末会附上TCP客户端。本文分为三部分&#xff0c;第一部分是在界面向TCP发送数据&#xff0c;第二部分是接收…...

[SQL Statements] 基本的SQL知识 之DDL针对数据库的基本操作

SQL Statements SQL语句的学习 之 DDL针对数据库的基本操作 什么是database 在 MySQL 中&#xff0c;Database&#xff08;数据库&#xff09;是一组有组织的数据集合&#xff0c;可以存储和管理相关数据的容器。一个数据库可以包含多个表&#xff08;Table&#xff09;&…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...