Redis 7.0中Lua脚本不会被内存淘汰中断,因淘汰策略仅作用于key-value数据,不涉及脚本运行时逻辑;OOM错误是执行前内存水位超限导致拒绝启动脚本,而非中断运行中脚本。

Redis 7.0 中 Lua 脚本不会因为内存淘汰而被中断——淘汰机制压根不碰脚本,SCRIPT LOAD 和 FUNCTION LOAD 注册的逻辑都不在淘汰范围内。
为什么Lua脚本根本不会被内存淘汰中断
Redis 的内存淘汰(maxmemory-policy)只作用于数据库中的 key-value 数据,比如 SET、HSET、ZADD 写入的内容。而 Lua 脚本(无论用 EVAL、SCRIPT LOAD 还是 FUNCTION LOAD)属于服务端运行时逻辑,加载后存在独立内存区,不计入 used_memory_dataset,也不响应 allkeys-lru 或 volatile-ttl 等策略。
常见误判场景:
- 看到
(error) OOM command not allowed when used memory > 'maxmemory'就以为是“脚本被干掉了”——其实这是 Redis 在执行前检查内存水位,拒绝启动新脚本,不是中断已运行的脚本 - 把
redis.call()返回大结果导致内存峰值,和“淘汰机制杀脚本”混淆——前者是运行时瞬态占用,后者根本不存在
真正会卡住或失败的内存相关问题在哪
脚本出问题,往往不是被“淘汰”,而是触发了 Redis 的前置内存准入控制或运行时资源耗尽:
-
OOM错误本质是:脚本调用redis.call("hgetall", "bigkey")等命令,一次性加载大量数据进 Lua 栈,导致 Redis 当前used_memory超过maxmemory,于是拒绝执行整个脚本(连入口都不放行) -
lua-time-limit超时后返回BUSY,不是淘汰,而是脚本还在跑、但连接被断开;此时若脚本已执行写命令(如redis.call("INCR")),SCRIPT KILL会失效,节点持续 BUSY - 用
redis.pcall()在循环中反复捕获错误却不设res = nil,导致 Lua 栈累积大量未释放 table,脚本退出前不 GC,可能撑爆栈或触发 OOM 拒绝后续调用
实操上怎么避免脚本因内存问题失败
关键不是防“淘汰”,而是控输入、限规模、设兜底:
- 所有集合类操作前加守卫:
if #KEYS > 1000 then return {err="too many keys"} end - 避免无节制拼接:
table.concat(big_list)前先if #big_list > 500 then return {err="list too long"} end - 用
redis.call()替代redis.pcall()处理确定性失败场景(如限流计数),减少中间表堆积 - 客户端必须设超时:Go 用
context.WithTimeout(ctx, 2500 * time.Millisecond),Python 用socket_timeout=2.5,确保在lua-time-limit=2000前主动断连 - 别把几 MB 的 JSON 字符串硬编码进函数体——
FUNCTION LOAD时就固定占内存,且无法被任何策略回收
最易被忽略的一点:OOM 报错看似来自脚本,实际根源常在 key 本身——比如一个 HGETALL 返回 50MB 数据,问题不在脚本,而在那个不该存在的大 Hash。查 MEMORY USAGE 和 SCAN 找大 key,比调优脚本更治本。


















