flushdb或flushall已足够多数场景重置缓存,无需lua;仅条件清理、状态校验等才需lua;禁用keys,须用scan分批del;evalsha上线前须script load、script exists校验并设fallback。

直接用 FLUSHDB 或 FLUSHALL 就够了?
多数场景下,真没必要写 Lua 脚本去“重置缓存”——FLUSHDB(清空当前数据库)或 FLUSHALL(清空所有数据库)本身就是原子、高效、内置的命令。Lua 脚本在这里没有额外价值,反而引入解析开销和维护成本。只有当你需要带条件地清理(比如只删某类 key)、或在清理前做状态校验/记录日志时,才值得上脚本。
EVAL 中调用 FLUSHDB 的常见错误
有人会写类似 EVAL "redis.call('FLUSHDB')" 0,这看似无害,但实际踩坑:
-
FLUSHDB和FLUSHALL在 Lua 脚本里**不能带参数**,写成redis.call("FLUSHDB", "ASYNC")会报错ERR unknown command - Redis 7.0+ 支持
FLUSHDB ASYNC,但该语法**不被 Lua 环境识别**,必须走原生命令 - 脚本里调用
FLUSHDB后,后续命令仍会执行(除非显式return),容易误操作
真正需要 Lua 的重置场景:按前缀批量删除
当你要“重置某类缓存”(比如所有 user:* 或 config:*),又不想影响其他数据,这时 Lua 才有用武之地。核心是避免客户端先 KEYS 再循环 DEL —— KEYS 阻塞、不安全、不可靠。
正确做法是用 SCAN 游标分批处理:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
local cursor = "0"
local pattern = ARGV[1] or "*"
local count = tonumber(ARGV[2]) or 100
repeat
local res = redis.call("SCAN", cursor, "MATCH", pattern, "COUNT", count)
cursor = res[1]
local keys = res[2]
if #keys > 0 then
redis.call("DEL", unpack(keys))
end
until cursor == "0"
return 1
调用方式:EVAL <script> 0 user:* 500</script>(匹配 user:*,每次扫 500 个 key)
- 必须用
SCAN,禁用KEYS—— 否则线上 Redis 可能卡死 -
unpack(keys)在 key 数量超 10K 时可能触发 Lua 栈溢出,生产环境建议加if #keys > 1000 then break end限流 - pattern 参数必须传入,硬编码在脚本里会导致无法复用
EVALSHA 上线前必须做的三件事
脚本不是写完就能扔进生产环境的。上线前漏掉任何一步,都会导致 NOSCRIPT 错误或逻辑错乱:
- 先用
SCRIPT LOAD提交脚本,拿到 SHA1 值(比如"8b6c4d...") - 用
SCRIPT EXISTS检查目标 Redis 实例是否已缓存该 SHA1(集群环境每个分片都要检查) - 降级兜底:调用
EVALSHA失败时,捕获NOSCRIPT错误,自动 fallback 到EVAL+ 完整脚本源码
最容易被忽略的是:脚本内容变更后,SCRIPT LOAD 必须重新执行,否则旧 SHA1 仍指向老逻辑 —— 这不是缓存失效,是逻辑静默错误。










