redis lua脚本执行报noscript异常,本质是evalsha所用sha值未在服务端缓存,主因包括:未调用script load、加载与执行sha不一致、redis重启清空缓存、集群下脚本未路由到同一节点或客户端硬编码失效sha。

Redis Lua脚本加载失败,90%以上不是语法错,而是脚本没被正确加载到服务端——要么根本没调用 SCRIPT LOAD,要么加载后用错了 EVALSHA 的 SHA 值,要么 Redis 重启清空了缓存却没重载。
为什么 EVALSHA 报 NOSCRIPT No matching script
这是最常见现象,本质是 Redis 根本没缓存对应 SHA 的脚本。原因包括:
- 脚本从未执行过
SCRIPT LOAD,或加载时传入的字符串和后续EVALSHA的 SHA 不一致(比如换行符不同、空格增删、注释差异) - Redis 服务重启过,内存中所有已加载脚本全部丢失
- 集群模式下,
SCRIPT LOAD只发到了某个节点,但EVALSHA路由到了另一个节点(没加载过该脚本) - 客户端硬编码了 SHA 值,而实际脚本内容已变更,SHA 自然失效
如何确保脚本一定被加载(启动期预加载)
别依赖第一次请求“懒加载”,尤其在生产环境。推荐在应用启动时主动加载并缓存 SHA:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
redis-cli --eval或客户端 API 显式调用SCRIPT LOAD,拿到返回的 SHA(如"241e586a7e8b2c3d...") - 把 SHA 存进配置或静态字段,后续统一用
EVALSHA+ 该 SHA 执行 - Spring Boot 场景下,可在
@PostConstruct方法里完成加载;Redisson 用户应开启useScriptCache = true并配合scriptLoad() - 注意:若脚本内容变更,必须同步更新 SHA 缓存,否则仍会报
NOSCRIPT
Windows 写的脚本传到 Linux 运行失败?先查换行符
脚本在 Windows 编辑器里保存,默认是 CRLF(\r\n),而 Linux Redis 只认 LF(\n)。遇到 ERR Error running script 且提示含 $'\r': command not found 或解析异常,基本就是它。
- 确认方式:
file script.lua输出含CRLF;或xxd script.lua | head -n 1看是否出现0d 0a - 修复命令(Linux 上运行):
dos2unix script.lua(最稳)或sed -i $'s/\r$//' script.lua - 预防:VS Code 右下角点
CRLF→ 切成LF;项目加.editorconfig,写入[*.lua]\nend_of_line = lf
集群环境下脚本加载必须带路由键
Redis Cluster 不共享脚本缓存,每个分片独立维护。如果脚本操作多个 key,必须保证这些 key 落在同一 slot,否则 SCRIPT LOAD 和 EVALSHA 可能打到不同节点。
- 加载时:用
redis-cli -c --eval script.lua key1 key2 , arg1 arg2,逗号前是 keys,逗号后是 args;Redis 会自动按第一个 key 路由 - 执行时:
EVALSHA的 keys 参数不能为空,且至少有一个 key 用于确定目标节点;若操作跨 slot 的 key,需拆成多个脚本或改用单节点 Redis - 客户端如 Jedis/Redisson 默认不处理跨 slot 脚本,出错时会抛
JedisNoScriptException或类似异常,而非静默失败
真正麻烦的不是某次加载失败,而是脚本被多人编辑、CI 构建自动拉取、容器镜像打包时悄悄混入 \r 或 SHA 失效——把这些检查项(file、sed -i 's/\r$//'、启动时 SCRIPT EXISTS 校验)写进部署 checklist,比线上报错再排查快得多。










