Redis 2.6引入Lua脚本,核心为解决多命令组合非原子执行与网络往返开销大两大痛点;其支持条件判断、循环及中间结果处理,弥补MULTI/EXEC事务缺陷,并通过EVALSHA实现脚本复用与超时管控。

Redis 2.6 引入 Lua 脚本,核心是解决「多命令组合操作无法原子执行」和「网络往返开销不可控」这两个分布式架构中最常踩坑的痛点。它不是锦上添花,而是把原本靠客户端拼逻辑、靠重试兜底、靠业务层加锁才能勉强实现的场景,直接压进服务端一次跑完。
为什么 MULTI/EXEC 事务在分布式场景下不够用
Redis 的 MULTI/EXEC 确实能打包命令,但它不支持条件判断和中间结果处理。比如「只有 key 不存在才 SET,且成功后返回 1」这种逻辑,MULTI 做不了——它无法读取 EXISTS 结果再决定是否 SET。
-
MULTI/EXEC是纯命令队列,没有 if/else、循环、变量赋值能力 - 客户端必须先
GET再判断再发SET,两次网络往返 + 竞态窗口(A 判断不存在,B 插入,A 还是 SET 了) - 分布式锁、限流、库存扣减等场景,本质都依赖「读-判-写」原子性,
MULTI天然缺失这一环
为什么网络 RTT 在高并发分布式系统里是硬伤
一个秒杀预减库存逻辑,如果用客户端串行调用:GET → 判断余量 → DECR → EXPIRE,4 次往返。在跨机房或容器网络延迟动辄 1–5ms 的情况下,单请求耗时轻松突破 20ms,QPS 直接被卡死。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- Lua 脚本把这 4 步压成 1 次
EVAL请求,网络开销降为 1×RTT - 脚本内所有
redis.call()调用都在服务端内存完成,无额外序列化/调度成本 - 注意:
redis.pcall()不会中断脚本,适合需要容错的分支逻辑,但别滥用——错误捕获本身有开销
为什么「脚本复用」对微服务架构特别关键
多个 Java/Go/Python 服务共用一套限流规则,如果各自实现 Lua 脚本并 EVAL 发送,不仅带宽浪费,更可怕的是脚本内容稍有差异(比如 TTL 单位是秒还是毫秒),就会导致行为不一致。
- 用
SCRIPT LOAD预加载脚本,得到固定SHA1,所有服务统一调用EVALSHA - 脚本变更时只需更新一次
SCRIPT FLUSH+ 重载,无需重启任何客户端 - 隐患:Redis 重启后脚本丢失,
EVALSHA会报NOSCRIPT错误——必须在客户端做 fallback 到EVAL或自动重载
真正容易被忽略的点是超时控制:lua-time-limit 默认 5 秒,但一个没加 return 的无限循环脚本会让整个 Redis 变成只读状态,后续所有命令都会收到 Busy Redis is busy running a script。这不是脚本写错了的问题,而是你根本没意识到——它卡住的是整个实例,不是单个连接。

















