不能用lua-time-limit控制内存,因其仅限制执行时长(毫秒),不约束内存分配;脚本可能在超时前就通过table.insert或HGETALL等操作耗尽内存,导致OOM或淘汰策略失效。

Redis 本身不提供 Lua 脚本内存硬限制,所谓“限制内存”只能靠编写习惯和运行约束来规避 OOM;循环次数则必须手动设上限,否则极易触发 BUSY Redis is busy running a script 或超时中断。
为什么不能用 lua-time-limit 控制内存?
lua-time-limit 只管执行时长(毫秒),不管内存。脚本可能在 100ms 内就用 table.insert 构造出百万级数组,或通过 redis.call("HGETALL", "huge_hash") 一次性加载几十 MB 数据——这些操作完成时远未超时,但 used_memory_peak_human 已飙升,后续淘汰策略失效甚至触发 OOM killer。
常见错误现象:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- INFO memory 中
used_memory_peak_human比used_memory_human高出数十 MB,且 SCRIPT FLUSH 后回落明显 - 脚本返回
OOM command not allowed when used memory > 'maxmemory',但redis-cli --stat显示内存使用平稳
如何安全限制循环次数?
所有 for / while 循环必须带明确、保守的上界,且该上界应由客户端传入并校验,不能依赖 KEY/ARGV 动态长度无约束展开。
- 禁止写
for i = 1, #KEYS do ... end—— 若客户端误传 10 万个 key,脚本直接卡死 - 正确写法:
for i = 1, math.min(#KEYS, 100) do ... end,硬编码上限 + 客户端预检 - 嵌套循环更危险:两层各 100 次 → 实际 10000 次,建议单层 ≤ 50,禁用双层以上
- 每次循环内避免调用
redis.call(),尤其不能在循环里做HGETALL或LRANGE key 0 -1
哪些操作会悄悄吃掉大量内存?
不是大循环才耗内存,几个常见低感知操作更易踩坑:
-
redis.call("HGETALL", key):Hash 字段超 1 万时,返回结果序列化后常达数 MB,Lua table 解析再存一份,内存翻倍 - 字符串拼接:
res = res .. item每次都分配新 string,改用table.insert(buf, item)+table.concat(buf) - 未预分配的 table:
local t = {}后反复table.insert(t, x),触发多次 realloc,碎片率升高 - JSON 解析:
cjson.decode()加载大 JSON 字符串(如令牌桶状态)会生成深层嵌套 table,GC 延迟明显
真正有效的内存控制,是把“数据搬运”交给客户端分批拉取,脚本只做原子判断与轻量计算——比如限流脚本只 INCR 和 EXPIRE,别让它解析用户行为日志。

















