不能在Lua脚本中直接调用SCAN或KEYS批量删前缀key:SCAN未白名单报错,KEYS会阻塞主线程;正确做法是客户端分批SCAN过滤key后,传入极简DEL脚本执行。

不能直接在 Lua 脚本里调用 SCAN 或 KEYS 批量删前缀 key——前者因未列入白名单会报 ERR unknown command 'SCAN',后者会阻塞 Redis 主线程,线上等同于制造故障。
为什么 KEYS prefix* + DEL 的 Lua 脚本不能用于生产
这种写法看似简洁:redis.call('KEYS', pattern .. '*') 拿到所有匹配 key 再循环 DEL,但它有三个致命问题:
-
KEYS是全量遍历命令,在几万级 key 的实例上可能卡住 Redis 几百毫秒,引发请求堆积、超时雪崩 - 脚本执行期间无法被中断,一旦出错或超时,只能靠
SCRIPT KILL强杀,但若已执行部分DEL,状态不可回滚 - 返回的 key 列表过大(比如上万)时,Lua 脚本内存占用飙升,Redis 可能 OOM 或拒绝执行
正确做法:客户端驱动 SCAN + 原子 DEL 脚本
核心是把“扫描”和“删除”拆开:客户端分批 SCAN,过滤出匹配前缀的 key,再传给极简 Lua 脚本批量 DEL。这样每步都可控、可中断、不阻塞。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- SCAN 参数建议用
COUNT 100,太大易超时,太小网络开销高 - Lua 脚本只做一件事:
for i, key in ipairs(KEYS) do redis.call('DEL', key) end,不带任何逻辑判断 - 每次传入的
KEYS数量控制在 1000 以内,避免单次命令包超限(Redis 默认proto-max-bulk-len为 512MB,但实际建议 ≤10KB) - 务必检查
SCAN返回游标:当 new_cursor == "0" 时才算真正扫完,否则继续下一轮
容易踩的坑:游标处理、空列表、Cluster 兼容性
常见错误不是脚本写错,而是调用方式不对:
- 忽略游标类型:
SCAN返回的游标是字符串(如"1234"),不是数字,客户端不能直接+1或强转 int - 传空
KEYS给 Lua 脚本:若某批SCAN结果没匹配到任何 key,仍调用脚本会导致ipairs({})不执行循环,但浪费一次 round-trip;应提前判空跳过 - 在 Redis Cluster 下硬编码 key 名:脚本中所有操作 key 必须通过
KEYS[1]等传入,不能写死"prefix:user:123",否则路由失败报CROSSSLOT - 忘记加休眠:每轮 SCAN+DEL 后建议
time.sleep(0.005)(5ms),防止压垮 Redis,也方便运维随时中止流程
脚本要不要 SCRIPT LOAD 缓存?
要,但只对高频复用的固定脚本。比如你每天定时清理 tmp: 前缀,就该先 SCRIPT LOAD 得到 SHA1,后续用 EVALSHA 调用。否则每删一次都传几百字节脚本体,既浪费带宽又推高 number_of_cached_scripts——已有案例因缓存 987 万个脚本导致内存居高不下,最后靠 SCRIPT FLUSH 救急。

















