Redis(63)Redis的Lua脚本如何使用?

Redis 提供了对 Lua 脚本的支持,使得用户可以在服务器端执行原子操作,从而能够降低网络开销、提高性能和确保操作的原子性。以下是关于如何使用 Redis 的 Lua 脚本的详细指南,并结合实例代码进行说明。

1. 使用 Lua 脚本的基本命令

Redis 提供了两个主要命令来执行 Lua 脚本:

  • EVAL
  • EVALSHA

EVAL 命令

EVAL 命令用于直接执行 Lua 脚本。

语法:

sh 复制代码
EVAL script numkeys key [key ...] arg [arg ...]
  • script: Lua 脚本。
  • numkeys: 脚本中的键的数量。
  • key [key ...]: 传递给脚本的键。
  • arg [arg ...]: 传递给脚本的参数。

EVALSHA 命令

EVALSHA 命令用于执行已经缓存过的 Lua 脚本,其 SHA1 哈希值作为脚本标识符。

语法:

sh 复制代码
EVALSHA sha1 numkeys key [key ...] arg [arg ...]

2. Lua 脚本示例

示例 1:简单的计数器

我们编写一个简单的 Lua 脚本来实现计数器。

lua 复制代码
local current = redis.call("GET", KEYS[1])
if current == false then
    redis.call("SET", KEYS[1], 1)
    return 1
else
    redis.call("INCR", KEYS[1])
    return redis.call("GET", KEYS[1])
end

在 Redis 中执行此脚本:

sh 复制代码
redis-cli EVAL "local current = redis.call('GET', KEYS[1]); if current == false then redis.call('SET', KEYS[1], 1); return 1; else redis.call('INCR', KEYS[1]); return redis.call('GET', KEYS[1]); end" 1 mycounter

示例 2:条件更新

一个示例 Lua 脚本,用于在满足特定条件下更新键的值。

lua 复制代码
local currentValue = redis.call("GET", KEYS[1])
if tonumber(currentValue) < tonumber(ARGV[1]) then
    redis.call("SET", KEYS[1], ARGV[1])
    return ARGV[1]
else
    return currentValue
end

执行此脚本:

sh 复制代码
redis-cli EVAL "local currentValue = redis.call('GET', KEYS[1]); if tonumber(currentValue) < tonumber(ARGV[1]) then redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]; else return currentValue; end" 1 mykey 100

3. Lua 脚本与 Redis 事务

Lua 脚本的一个重要特点是它们是原子的。在脚本执行期间,Redis 不会中断脚本去处理其他命令。

示例 3:原子性操作

lua 复制代码
local balance = redis.call("GET", KEYS[1])
local amt = tonumber(ARGV[1])
if balance == false then
    redis.call("SET", KEYS[1], amt)
else
    redis.call("INCRBY", KEYS[1], amt)
end
return redis.call("GET", KEYS[1])

执行此脚本:

sh 复制代码
redis-cli EVAL "local balance = redis.call('GET', KEYS[1]); local amt = tonumber(ARGV[1]); if balance == false then redis.call('SET', KEYS[1], amt); else redis.call('INCRBY', KEYS[1], amt); end; return redis.call('GET', KEYS[1]);" 1 user:balance 50

4. 使用 EVALSHA 执行缓存脚本

首先,我们使用 EVAL 命令加载脚本并获取其 SHA1 哈希值。

示例 4:使用 EVALSHA

  1. 加载脚本并获取 SHA1 哈希值:
sh 复制代码
$ redis-cli SCRIPT LOAD "local balance = redis.call('GET', KEYS[1]); local amt = tonumber(ARGV[1]); if balance == false then redis.call('SET', KEYS[1], amt); else redis.call('INCRBY', KEYS[1], amt); end; return redis.call('GET', KEYS[1]);"

"e0c7a2d6c64616e9a7e1a0c0e51c8eb5bdbf7cbb"
  1. 使用 EVALSHA 执行脚本:
sh 复制代码
$ redis-cli EVALSHA "e0c7a2d6c64616e9a7e1a0c0e51c8eb5bdbf7cbb" 1 user:balance 50

5. Lua 脚本的调试

为了调试 Lua 脚本,可以使用 Redis 提供的日志功能。可以通过 redis.log 将信息写入日志。

示例 5:调试脚本

lua 复制代码
redis.log(redis.LOG_NOTICE, "Script started")
local balance = redis.call("GET", KEYS[1])
if balance == false then
    redis.call("SET", KEYS[1], 0)
    balance = 0
end
redis.log(redis.LOG_NOTICE, "Current balance: " .. balance)
return balance

执行脚本:

sh 复制代码
redis-cli EVAL "redis.log(redis.LOG_NOTICE, 'Script started'); local balance = redis.call('GET', KEYS[1]); if balance == false then redis.call('SET', KEYS[1], 0); balance = 0; end; redis.log(redis.LOG_NOTICE, 'Current balance: ' .. balance); return balance;" 1 user:balance

查看日志:

sh 复制代码
tail -f /var/log/redis/redis.log

6. 使用 Lua 脚本操作 Redis 数据结构

Lua 脚本不仅可以操作简单键值对,还可以操作 Redis 提供的多种数据结构,如列表、集合、哈希等。

示例 6:操作列表

lua 复制代码
local listName = KEYS[1]
local newItem = ARGV[1]
redis.call("RPUSH", listName, newItem)
return redis.call("LRANGE", listName, 0, -1)

执行脚本:

sh 复制代码
redis-cli EVAL "local listName = KEYS[1]; local newItem = ARGV[1]; redis.call('RPUSH', listName, newItem); return redis.call('LRANGE', listName, 0, -1);" 1 mylist item1

总结

通过 Lua 脚本,Redis 可以在服务器端执行复杂的逻辑操作,保证操作的原子性和高效性。本文详细介绍了如何使用 EVALEVALSHA 命令执行 Lua 脚本,并给出了多个示例代码,包括操作基本键值对和复杂数据结构、调试脚本和使用缓存脚本。通过合理使用 Lua 脚本,可以大大提升 Redis 的性能,并简化客户端的逻辑处理。

相关推荐
嘉伟桑1 小时前
Python调用电价API返回JSON示例:分时电价、现货电价和字段解析
后端
武子康1 小时前
Shippy:确定性工具、会话级 Sandbox 与 Live-Data Eval(4 类收敛 + 7 步实现方案 + 6 类评测指标)
前端·人工智能·后端
我叫黑大帅2 小时前
我为什么单一消费者的场景下,要用 Redis List 当消息队列?
redis·后端·面试
AskHarries2 小时前
文件上传系统
后端
止语Lab3 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活3 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困3 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn3 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
用户298698530143 小时前
Python 实现 Excel 与 Markdown 互转的实用指南
后端·python·excel
用户77283104908403 小时前
krono-job:零侵入、单二进制交付的分布式任务调度平台(开源)
后端