不是。redis lua脚本执行期间仍会触发内存淘汰,因freememoryifneeded()在eval前及脚本内写入时均被调用,且activeexpirecycle()持续运行,原子性不阻断内存管理。

Redis Lua脚本执行期间真的不会触发内存淘汰吗?
不是。Lua脚本的原子性 ≠ 内存淘汰被禁用。Redis 会照常执行 evict.c 中的淘汰逻辑,只要 maxmemory 已设且内存超限,淘汰就可能发生——哪怕脚本正在运行中。
为什么很多人误以为“原子性 = 淘汰暂停”?
这个误解源于对“原子性”的窄化理解:Lua 脚本确实以单线程、不可中断方式执行,所有命令按序完成,中间不会插入其他客户端请求;但它不阻止 Redis 自身的后台内存管理行为,比如:
-
activeExpireCycle()仍在定时扫描过期 key(惰性+定期删除机制照常工作) -
freeMemoryIfNeeded()在每次命令入口(包括EVAL执行前)都会被检查 —— 如果此时已超限,Redis 会先尝试淘汰一批 key,再继续执行脚本 - 脚本内部若调用
redis.call("SET", ...)写入新 key,该写入操作本身可能触发淘汰(尤其在allkeys-lru等策略下)
如何验证脚本执行中是否发生淘汰?
最直接的方式是监控淘汰统计和内存变化:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 执行前运行
INFO memory记下used_memory和evicted_keys - 在脚本里插入一个明显内存开销的操作,例如:
redis.call("SET", "bigkey", string.rep("x", 1024*1024)) - 脚本执行后再次
INFO memory,若evicted_keys增加,说明淘汰已发生 - 更细粒度可开启
CONFIG SET notify-keyspace-events "Ee"监听__keyevent@0__:evicted事件
真正能规避淘汰风险的做法
靠“等脚本跑完再淘汰”不现实。必须从配置与脚本设计两头控制:
- 设置足够宽松的
maxmemory,留出脚本执行所需的峰值内存余量(特别是批量写入或构造大对象时) - 避免在 Lua 中做高内存消耗操作:如拼接超长字符串、
redis.call("HMSET", ...)传入数百个 field、或反复table.insert后转 JSON - 改用
noeviction策略 + 客户端兜底:当EVAL返回(error) OOM command not allowed时,由业务层降级或重试 - 对关键脚本预估内存占用,配合
MEMORY USAGE和DEBUG OBJECT(仅开发环境)做压测验证
脚本的原子性只管指令顺序和隔离性,不管内存够不够——这点最容易被忽略,也最常在线上引发静默驱逐和数据不一致。










