广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >redis中lua脚本使用教程
  • 633
分享到

redis中lua脚本使用教程

2024-04-02 19:04:59 633人浏览 独家记忆
摘要

目录一、背景二、使用lua脚本三、lua和Redis数据类型转换四、lua脚本中输出日志五、一个简单限流的案例六、lua脚本的debug七、参考文档一、背景 在使用redis的过程中

一、背景

在使用redis的过程中,发现有些时候需要原子性去操作redis命令,而redis的lua脚本正好可以实现这一功能。比如: 扣减库存操作、限流操作等等。
redis的pipelining虽然也可以一次执行一组命令,但是如果在这一组命令的执行过程中,需要根据上一步执行的结果做一些判断,则无法实现。

二、使用lua脚本

Redis中使用的是 Lua 5.1 的脚本规范,同时我们编写的脚本的时候,不需要定义 Lua 函数。同时也不能使用全局变量等等。

1、lua脚本的格式和注意事项

1、格式

EVAL script numkeys key [key ...] arg [arg ...]

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],ARGV[2]}" 1 key1 arg1 arg2
1) "key1"
2) "arg1"
3) "arg2"
127.0.0.1:6379>

2、注意事项

Lua脚本中的redis操作的key最好都是通过 KEYS来传递,而不要写死。否则在Redis Cluster的情况下可能有问题.

1、好的写法

127.0.0.1:6379> eval "return redis.call('set',KEYS[1],'zhangsan')" 1 username
OK
127.0.0.1:6379> get username
"zhangsan"

redis命令操作的key是通过KEYS获取的。

2、差的写法

127.0.0.1:6379> eval "return redis.call('set','username','zhangsan')" 0
OK
127.0.0.1:6379> get username
"zhangsan"

redis命令操作的key是直接写死的。

2、将脚本加载到redis中

需求: 此处定义一个lua脚本,将输入的参数的值+1返回。

注意:

当我们把 lua脚本加载到redis中,这个脚本并不会马上执行,而是会缓存起来,并且返回sha1校验和,后期我们可以通过 EVALSHA 来执行这个脚本。

此处我们记住这个脚本加载后返回的hash值,在下一步执行的时候需要用到。

127.0.0.1:6379> script load "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379>

3、执行lua脚本

1、通过eval执行

127.0.0.1:6379> eval "return tonumber(KEYS[1]) + 1" 1 100
(integer) 101
127.0.0.1:6379>

2、通过evalsha执行

ef424d378d47e7a8b725259cb717d90a4b12a0de的值为上一步通过 script load加载脚本后获取的。

127.0.0.1:6379> evalsha ef424d378d47e7a8b725259cb717d90a4b12a0de 1 100
(integer) 101
127.0.0.1:6379>

通过 evalsha 执行的好处是可以节省带宽。如果我们的lua脚本比较长,程序在执行的时候将lua脚本发送到redis服务器则可能耗费的带宽多,如果发送的是hash值的话,则耗费的带宽少。

4、判断脚本是否在redis服务器缓存中

127.0.0.1:6379> script load "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379> script exists ef424d378d47e7a8b725259cb717d90a4b12a0de
1) (integer) 1
127.0.0.1:6379> script exists not-exists-sha1
1) (integer) 0
127.0.0.1:6379>

5、清空服务器上的脚本缓存

注意:
我们无法清除某一个脚本的缓存,只可以清楚所有的缓存,一般情况下没有必要清楚,因为即使有大量的脚本也不会太占用服务器内存。

127.0.0.1:6379> script load "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379> script exists ef424d378d47e7a8b725259cb717d90a4b12a0de
1) (integer) 1
127.0.0.1:6379> script flush
OK
127.0.0.1:6379> script exists ef424d378d47e7a8b725259cb717d90a4b12a0de
1) (integer) 0

6、杀死正在运行的脚本

127.0.0.1:6379> script kill

注意:

  • 该命令只可以杀死正在运行的 只读脚本
  • 对于修改了数据的脚本,无法使用此命令杀死,只能使用 shutdown nosave命令。
  • 脚本执行的默认超时时间5分钟,可以通过redis.conf配置文件的lua-time-limit配置项修改。
  • 脚本即使到达了超时时间,也不会停止执行,因为这违反了lua脚本的原子性。

三、lua和redis数据类型转换

Lua的数据类型和Redis的数据类型存在一对一的转换关系,如果将Redis类型转换成Lua类型,然后在转换成Redis类型,那么结果和初试值是一致的。

1、类型转换

Redis to Luaconversion table.

  • Redis integer reply -> Lua number
  • Redis bulk reply -> Lua string
  • Redis multi bulk reply -> Lua table (may have other Redis data types nested)
  • Redis status reply -> Lua table with a single ok field containing the status
  • Redis error reply -> Lua table with a single err field containing the error
  • Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type

Lua to Redisconversion table.

  • Lua number -> Redis integer reply (the number is converted into an integer)
  • Lua string -> Redis bulk reply
  • Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)
  • 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.

2、额外的转换规则

  1. Lua的布尔类型,Lua的True会转换成Redis的1

3、3个重要规则

1. 数字类型

在Lua中,只有一个number类型,整数和浮点数之间没有区别,如果我们在Lua中返回一个浮点数,实际返回的是一个整数,如果要返回浮点数,需要以字符串的方式返回。

127.0.0.1:6379> eval "return 3.98" 0
(integer) 3
127.0.0.1:6379> eval "return '3.98'" 0
"3.98"

2. lua数组存在nil

当 Redis 将 Lua 数组转换为 Redis 协议时,如果遇到 nil,则转换会停止。即 nil 后的值都不会返回。

127.0.0.1:6379> eval "return {1,2,'data',nil,'can not return value','vv'}" 0
1) (integer) 1
2) (integer) 2
3) "data"
127.0.0.1:6379>

3. Lua的Table类型包含建和值

出现这种情况返回的redis的是一个空数组

127.0.0.1:6379> eval "return {key1 ='value1',key2='value2'}" 0
(empty array)
127.0.0.1:6379>

四、lua脚本中输出日志

这个一般调试我们的脚本的时候比较有用。

redis.log(loglevel,message)

loglevel的取值范围:

  • redis.LOG_DEBUG
  • redis.LOG_VERBOSE
  • redis.LOG_NOTICE
  • redis.LOG_WARNING

举例:

五、一个简单限流的案例

1、需求

在 1s 之内,方法最大的并发只能是 5。

1s 和 5 当作参数传递。

2、实现步骤

1、编写lua脚本


-- 输出用户传递进来的参数
for i, v in pairs(KEYS) do
    redis.log(redis.LOG_NOTICE, "limit: key" .. i .. " = " .. v)
end
for i, v in pairs(ARGV) do
    redis.log(redis.LOG_NOTICE, "limit: argv" .. i .. " = " .. v)
end

-- 限流的key
local limiTKEy = tostring(KEYS[1])
-- 限流的次数
local limit = tonumber(ARGV[1])
-- 多长时间过期
local expireMs = tonumber(ARGV[2])

-- 当前已经执行的次数
local current = tonumber(redis.call('get', limitKey) or '0')

-- 设置一个断点
redis.breakpoint()

redis.log(redis.LOG_NOTICE, "limit key: " .. tostring(limitKey) .. " 在[" .. tostring(expireMs) .. "]ms内已经访问了 " .. tostring(current) .. " 次,最多可以访问: " .. limit .. " 次")

-- 限流了
if (current + 1 > limit) then
    return { true }
end

-- 未达到访问限制
-- 访问次数+1
redis.call("incrby", limitKey, "1")
if (current == 0) then
    -- 设置过期时间
    redis.call("pexpire", limitKey, expireMs)
end

return { false }

2、程序中执行lua脚本

完整代码: https://gitee.com/huan1993/spring-cloud-parent/tree/master/SpringBoot/springboot-redis-lua

六、lua脚本的debug

当我们编写好了lua脚本后,如果在执行的过程中发生了错误,那么我们如何该如何解决呢?此处我们来了解下如何debug lua 脚本。

1、lua脚本中的几个小命令

在 脚本中打一个断点

redis.breakpoint()

2、断点调试

1、执行命令


redis-cli --ldb --eval limit.lua invoked , 1 1000

limit.lua 需要debug的lua文件
invoked 为传递到 lua 脚本中 KEYS 的值
1 和 1000 为传递到 lua 脚本中 ARGV 的值

, 分割 出 KEYS 和 ARGV 的值

2、一些debug指令

  • help: 列出可用的debug指令
  • sn: 运行到当前行并停止 (此时当前行还未执行)
  • c:运行到下个断点,即运行到lua脚本中存在 redis.breakpoint()方法的地方
  • list:列出当前行周围的一些源码
  • p:打印出所有的 local 变量的值
  • p <var>:打印具体的某个 local 变量的值
  • r:执行 redis 命令

-- eg:
r set key value
r get key

3、debug运行结果

七、参考文档

Https://redis.io/topics/ldb

https://redis.io/commands/eval

到此这篇关于redis中lua脚本的简单使用的文章就介绍到这了,更多相关redis中lua脚本使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: redis中lua脚本使用教程

本文链接: https://www.lsjlt.com/news/155706.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • redis中lua脚本使用教程
    目录一、背景二、使用lua脚本三、lua和redis数据类型转换四、lua脚本中输出日志五、一个简单限流的案例六、lua脚本的debug七、参考文档一、背景 在使用redis的过程中...
    99+
    2022-11-12
  • redis中怎么使用lua脚本
    这篇文章给大家分享的是有关redis中怎么使用lua脚本的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一:Lua脚本说来也巧,redis的大老板给了你解决这种问题的方法,那就是L...
    99+
    2022-10-18
  • Redis中Lua脚本有什么用
    这篇文章给大家分享的是有关Redis中Lua脚本有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。redis lua 脚本相关命令这一小节的内容是基本命令,可粗略阅读后跳过,...
    99+
    2022-10-18
  • Java生态/Redis中如何使用Lua脚本
    文章目录 一、安装LUA1)简单使用 二、lua语法简介1、注释1)单行注释2)多行注释 2、关键字3、变量1)全局变量2)局部变量 4、数据类型1)Lua数组2)字符串操作 5、if-else6、循环1)fo...
    99+
    2023-08-19
    lua java redis
  • PHP和Redis中的LUA脚本使用方法
    PHP和Redis中的LUA脚本使用方法LUA 是一种轻量级的脚本语言,旨在提供高效的嵌入式扩展功能。Redis 是一种开源的 NoSQL 数据库,提供高效的键值存储和缓存功能。在 Redis 中使用 LUA 脚本可以大大提高数据处理效率和...
    99+
    2023-05-15
    PHP redis Lua脚本
  • Java生态/Redis中怎么使用Lua脚本
    本篇内容主要讲解“Java生态/Redis中怎么使用Lua脚本”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java生态/Redis中怎么使用Lua脚本”吧!一、安装LUAMac上安装LUA很简...
    99+
    2023-07-05
  • Redis中如何执行Lua脚本
    今天就跟大家聊聊有关Redis中如何执行Lua脚本,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。前言Redis从2.6版本开始引入对Lua脚本的支持...
    99+
    2022-10-18
  • Redis使用lua脚本的案例分析
    这篇文章主要介绍了Redis使用lua脚本的案例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。版本:自2.6.0起可用。时间复杂度:取决...
    99+
    2022-10-18
  • Redis中Lua脚本的使用和设置超时
    目录EVAL命令简介eval格式特性执行流程关于脚本超时SCRIPT KILL 命令SHUTDOWN NOSAVE 命令参考Redis提供了Lua脚本功能来让用户实现自己的原子命令,...
    99+
    2022-11-12
  • springboot中使用redis并且执行调试lua脚本
    目录原因:1、创建一个基本的web项目2、配置redis3、测试redis 的lua脚本4、技术点5、调试方式1、进入服务关闭关闭正在运行的服务器2、从命令行启动redis3、在lu...
    99+
    2022-11-13
  • Redis中lua脚本实现及其应用场景
    目录1. Redis Lua脚本概述2. Redis Lua脚本的优势3. Redis Lua脚本的应用场景4. Redis Lua脚本的使用方法5. Java中使用redis的lua脚本5.1. 添加Redis依赖 在...
    99+
    2023-04-20
    Redis lua脚本 Redis lua
  • 怎么用Redis Lua脚本实现ip限流
    这篇文章主要讲解了“怎么用Redis Lua脚本实现ip限流”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Redis Lua脚本实现ip限流”吧!引言分布式限流最关...
    99+
    2023-07-02
  • Redis调用Lua脚本及使用场景快速掌握
    目录一、阅读本文前置条件二、为什么需要Lua脚本三、学点Lua语法3.1.一个简单的例子3.2.仔细看下Lua脚本里的内容3.3. 复杂点的例子四、Lua脚本预加载五、一个修改 JS...
    99+
    2022-11-13
  • Redis进阶应用:Redis+Lua脚本实现复合操作
    一、引言Redis是高性能的key-value数据库,在很大程度克服了memcached这类key/value存储的不足,在部分场景下,是对关系数据库的良好补充。得益于超高性能和丰富的数据结构,Redis已...
    99+
    2022-10-18
  • 简介Lua脚本与Redis数据库的结合使用
    可能你已经听说过Redis 中嵌入了脚本语言,但是你还没有亲自去尝试吧? 这个入门教程会让你学会在你的Redis 服务器上使用强大的lua语言。 Hello, Lua! 我们的第一个Redis Lua ...
    99+
    2022-06-04
    脚本 数据库 简介
  • redis使用Lua脚本解决多线程下的超卖问题及原因解析
    目录一.多线程下引起的超卖问题呈现二.使用Lua脚本解决多线程下超卖的问题以及为什么三.为什么使用Lua脚本就能解决多线程下的超卖问题呢?一.多线程下引起的超卖问题呈现 1.1.我先...
    99+
    2023-05-19
    redis多线程超卖 lua脚本解决超卖问题
  • 如何使用Redis+Lua脚本实现计数器接口防刷功能
    这篇文章主要介绍如何使用Redis+Lua脚本实现计数器接口防刷功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!【实现过程】一、问题分析 如果set命令设置上,但是在设置失效时间时由于网络抖动等原因导致没...
    99+
    2023-06-29
  • Redis中Scan命令的基本使用教程
    前言 Redis中有一个经典的问题,在巨大的数据量的情况下,做类似于查找符合某种规则的Key的信息,这里就有两种方式, 一是keys命令,简单粗暴,由于Redis单线程这一特性,keys命令是以阻塞的方式执...
    99+
    2022-10-18
  • Nginx中使用Lua脚本与图片的缩略图处理的实现
    目录环境搭建Ubuntu 16.04Ubuntu 18.04图片缩略图环境搭建 Ubuntu 16.04 安装环境的脚本 #!/bin/bash apt-get update...
    99+
    2022-11-13
  • 10分钟内讲解Npm脚本使用教程
    目录引言1.什么是npm脚本?2.原则3.通配符4.传递参数5.执行顺序6.默认值7.钩子8.缩写形式9.变量10.常见脚本示例11.使用nrm管理npm镜像引言 使用Node进行开...
    99+
    2022-11-13
    Npm脚本教程 Npm 脚本
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作