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 天前
【短链接项目笔记】Day2 用户注册
java·redis·笔记·后端·spring
ChaITSimpleLove1 天前
基于 .NET Garnet 1.0.91 实现高性能分布式锁(使用 Lua 脚本)
分布式·.net·lua
羑悻的小杀马特1 天前
Lua vs C++:核心设计哲学差异——从“系统基石”到“灵活工具”的思维碰撞
c++·lua
rocksun1 天前
Tigris对象存储正式开源MCP OIDC身份提供商
redis·安全·微服务
摇滚侠1 天前
Redis 零基础到进阶,Spring Boot 整合 Redis,笔记93-99
spring boot·redis·笔记
ChristXlx1 天前
Linux安装redis(虚拟机适用)
linux·运维·redis
此生只爱蛋1 天前
【Redis】列表List类型
数据库·redis·缓存
菜鸟小九1 天前
redis实战(缓存)
数据库·redis·缓存
快乐就去敲代码@!1 天前
Boot Cache Star ⭐(高性能两级缓存系统)
spring boot·redis·后端·缓存·docker·压力测试
程可爱1 天前
详解Redis三种特殊类型数据结构(Bitmap、HyperLogLog、GEO)
redis