Redis 命令详解:Scripting / Functions 命令
摘要
- 本文基于
redis-7.4.7 - Redis官网:https://redis.io/
- Lua语法参考
Scripting / Functions 简介
- Redis Scripting / Functions 是 Redis 提供的一套“服务器端可编程执行机制”,允许客户端把逻辑发送到 Redis 内部执行,从而:
1 | 将多条命令合并为一次原子执行 |
Scripting / Functions 命令详解
一、Lua 脚本执行与管理
1.1 Sctipt 脚本执行(EVAL)
- 用于直接在 Redis 中执行 Lua 脚本。
| 命令 | 语法 | 参数说明 | 示例 | 说明 |
|---|---|---|---|---|
| EVAL | EVAL script numkeys key [key ...] arg [arg ...] |
script:Lua 脚本 numkeys:key 数量 |
EVAL "return redis.call('GET', KEYS[1])" 1 k1 |
直接执行脚本 |
| EVAL_RO | EVAL_RO script numkeys key [key ...] arg [arg ...] |
只读执行 | EVAL_RO "return redis.call('GET', KEYS[1])" 1 k1 |
副本安全 |
| EVALSHA | EVALSHA sha1 numkeys ... |
sha1:脚本摘要 | EVALSHA abc123 1 k1 |
缓存执行 |
| EVALSHA_RO | EVALSHA_RO sha1 numkeys ... |
只读缓存执行 | 同上 | 副本安全 |
-
核心特性
1 | 原子执行(单线程) |
1.2 脚本运行管理(SCRIPT)
-
用于管理 Lua 脚本缓存和执行状态。
-
将脚本加载到缓存中,避免多次执行相同脚本时都要重新发送脚本到 Redis 服务器。
-
不会持久化,redis重启后失效
| 命令 | 语法 | 参数说明 | 示例 | 说明 |
|---|---|---|---|---|
| SCRIPT LOAD | SCRIPT LOAD script |
加载脚本并返回 SHA1 | SCRIPT LOAD "return 1" |
预热,不会持久化,redis重启后失效 |
| SCRIPT EXISTS | SCRIPT EXISTS sha1 [sha1 ...] |
判断是否已缓存 | SCRIPT EXISTS abc123 |
校验 |
| SCRIPT FLUSH | SCRIPT FLUSH [ASYNC] |
清空脚本缓存 | SCRIPT FLUSH |
运维 |
| SCRIPT KILL | SCRIPT KILL |
终止正在执行脚本 | SCRIPT KILL |
紧急 |
| SCRIPT DEBUG | SCRIPT DEBUG YES|SYNC|NO |
脚本调试模式 | SCRIPT DEBUG YES |
调试 |
二、Redis Functions(函数库与调用)
-
Redis 7 引入,用于替代大规模 Lua 脚本管理。
2.1 函数调用
| 命令 | 语法 | 参数说明 | 示例 | 说明 |
|---|---|---|---|---|
| FCALL | FCALL function numkeys key [key ...] arg [arg ...] |
function:函数名 | FCALL stock.decr 1 stock:1 5 |
调用函数 |
| FCALL_RO | FCALL_RO function numkeys ... |
只读调用 | FCALL_RO metrics.get 1 k1 |
副本安全 |
2.2 函数库管理
-
FUNCTION LOAD加载的脚本会被持久化保存,重启redis依旧有效。
| 命令 | 语法 | 参数说明 | 示例 | 说明 |
|---|---|---|---|---|
| FUNCTION LOAD | FUNCTION LOAD [REPLACE] payload |
payload:函数源码 | FUNCTION LOAD <code> |
加载函数,会持久化 |
| FUNCTION LIST | FUNCTION LIST [LIBRARY lib] |
查看函数库 | FUNCTION LIST |
查询 |
| FUNCTION DELETE | FUNCTION DELETE library |
删除函数库 | FUNCTION DELETE mylib |
清理 |
| FUNCTION DUMP | FUNCTION DUMP |
导出函数库 | FUNCTION DUMP |
备份 |
| FUNCTION RESTORE | FUNCTION RESTORE dump [REPLACE] |
恢复函数库 | FUNCTION RESTORE <dump> |
恢复 |
| FUNCTION FLUSH | FUNCTION FLUSH [ASYNC] |
清空所有函数 | FUNCTION FLUSH |
高风险 |
| FUNCTION KILL | FUNCTION KILL |
终止正在运行的函数 | FUNCTION KILL |
紧急停止 |
| FUNCTION STATS | FUNCTION STATS |
运行统计 | FUNCTION STATS |
监控 |
-
Redis Functions 的优势
1 | 持久化(随 RDB / AOF 保存) |
Function 源码格式
1 | #!lua name=ratelimit -- 这是 Redis Function 专用头声明 |
示例
-
- 场景:分布式滑动窗口限流器(企业级)
1 | 业务背景 |
-
数据模型设计
| Key | 类型 | 示例 |
|---|---|---|
| rate:{userId} | ZSET | score=timestamp |
-
初始化数据
1 | # 假设 userId = 1001 |
Script 使用示例
-
脚本
1 | local rateKey = KEYS[1] |
-
调用脚本
1 | 127.0.0.1:6379> EVAL "local rateKey = KEYS[1] local maxReq = tonumber(ARGV[1]) local window = tonumber(ARGV[2]) local now = tonumber(ARGV[3]) local minTime = now - window redis.call(\"ZREMRANGEBYSCORE\", rateKey, 0, minTime) local count = tonumber(redis.call(\"ZCARD\", rateKey)) if count >= maxReq then return count end redis.call(\"ZADD\", rateKey, now, now) redis.call(\"PEXPIRE\", rateKey, window) return count+1" 1 rate:1001 5 60000 1705000003000 |
-
预热后调用
1 | 127.0.0.1:6379> SCRIPT LOAD "local rateKey = KEYS[1] local maxReq = tonumber(ARGV[1]) local window = tonumber(ARGV[2]) local now = tonumber(ARGV[3]) local minTime = now - window redis.call(\"ZREMRANGEBYSCORE\", rateKey, 0, minTime) local count = tonumber(redis.call(\"ZCARD\", rateKey)) if count >= maxReq then return count end redis.call(\"ZADD\", rateKey, now, now) redis.call(\"PEXPIRE\", rateKey, window) return count+1" |
SpringBoot 调用 Script
-
直接运行脚本
1 | String lua = """ |
-
预热脚本
1 | String lua = """ |
Function 使用示例
-
Function 源码
1 | #!lua name=ratelimit |
-
加载 Function
1 | # 加载 Function |
-
调用 Function
1 | # 调用 Function: FCALL function_name num_keys key [key ...] arg [arg ...] |
-
删除 Function
1 | FUNCTION DELETE ratelimit |
SpringBoot 调用 Function
-
目前 SpringBoot 仅支持 Lua 脚本,不支持 Function,需要自己封装代码
-
Function 的返回值仅支持返回字符串,其它类型会抛异常,这是因为
Lettuce + RedisTemplate对 FCALL 的返回类型推断存在缺陷,但对 byte[](字符串)是稳定可用的。
1 | String lua = """ |