redis 5.0下lua脚本性能瓶颈源于redis.call()滥用和未缓存脚本:应缓存读结果、批量执行命令、强制使用script load+evalsha,并禁用复杂计算与动态脚本。

直接结论:在 Redis 5.0 环境下,Lua 脚本的执行效率瓶颈几乎全来自 redis.call() 的滥用和脚本未缓存——不是 Lua 本身慢,而是每次调用都触发完整命令链路开销。
避免反复调用 redis.call()
Redis 5.0 的 Lua 执行仍是单线程,每次 redis.call() 都会走一遍命令解析、ACL 校验、键空间查找(哪怕 key 相同)、实际执行。这不是“函数调用”,而是模拟一次客户端请求。
- 错误写法:
redis.call('GET', KEYS[1])出现 3 次 → 实际执行 3 次完整 GET 流程 - 正确写法:
local val = redis.call('GET', KEYS[1]),后续直接用val - 批量读场景:用
redis.call('HMGET', KEYS[1], unpack(ARGV))替代循环调用redis.call('HGET', KEYS[1], ARGV[i]) - 写操作同理:用
MSET、ZADD(多 member-score 对)、HMSET(Redis 5.0 已支持)代替循环SET/HSET
必须用 SCRIPT LOAD + EVALSHA
Redis 5.0 不支持自动脚本缓存,EVAL 每次都传输、解析、编译脚本,几百字节的脚本在高频调用(如限流器)下,网络和 CPU 开销远超逻辑本身。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
SCRIPT LOAD返回 SHA1 值,客户端需自行缓存该值(比如存在本地 Map 或共享配置中) - 后续全部改用
EVALSHA <sha><numkeys> ...</numkeys></sha>,Redis 直接查缓存执行,跳过传输与编译 - 注意:
EVALSHA失败时(返回NIL),必须 fallback 到EVAL并重新SCRIPT LOAD,不能静默失败 - Redis 5.0 的
SCRIPT FLUSH会清空所有已加载脚本,升级或运维操作后需重载
别让 Lua 做它不该做的事
Redis 5.0 内置的 Lua 解释器(5.1 版本)没有 JIT,且受 lua-time-limit(默认 5 秒)硬限制。超时会导致 SCRIPT KILL 或更糟的 SHUTDOWN NOSAVE。
- 禁止:JSON 解析(
cjson.decode()未默认加载)、base64 编解码、正则匹配(string.match复杂模式)、大数组排序(table.sort数百元素以上) - 慎用:
os.time()/os.date()—— 依赖系统时钟,集群节点时间不同步会导致行为不一致;改用redis.call('TIME')或由客户端传入毫秒时间戳 - 允许但需控制规模:简单字符串拼接、数值计算、几十次以内的循环(如遍历 ARGV 中的 5~10 个 ID)
- 特别注意:Redis 5.0 不支持
loadstring或动态生成脚本,所有逻辑必须静态写死
真正卡住性能的,往往不是“脚本写了什么”,而是“脚本怎么被调用”——EVALSHA 是否稳定命中缓存、redis.call() 是否被当成普通函数反复调用、有没有把客户端该干的事硬塞进脚本里。这些点在 Redis 5.0 下不会自动优化,必须手动约束。










