基本一致,但7.x强化了上下文隔离与错误恢复;两者均用lua 5.1,语法、keys/argv机制完全兼容,6.2脚本可直接在7.4运行,唯需注意lua-time-limit超时后不回滚已执行命令。

Redis 6.x 与 7.x 的 EVAL / EVALSHA 行为是否一致?
基本一致,但 7.x 对脚本执行的上下文隔离和错误恢复做了隐式加固。两者都使用相同的 Lua 5.1 解释器(未升级),EVAL 和 EVALSHA 命令语法、参数规则、KEYS/ARGV 传参机制完全兼容。你把一个在 6.2 上跑通的脚本原样发给 7.4,只要不涉及已废弃的 Redis 命令(如 SCRIPT KILL 对函数无效),它一定也能执行成功。
但要注意:7.x 默认启用了更严格的 lua-time-limit 检查(仍为 5000ms),且超时中断后不会自动清理部分执行状态——比如脚本里已调用 redis.call('XADD', ...) 成功写入一条 Stream 消息,超时后这条消息不会回滚。这点和 6.x 完全相同,但因 7.x 更强调服务端逻辑可靠性,容易让人误以为“有回滚能力”。
Redis Functions 是不是 Lua 脚本的替代品?能直接迁移 EVAL 脚本过去吗?
不能直接迁移。FUNCTION LOAD 加载的是带 #!lua name=xxx 前缀的函数定义体,结构和语义都不同于传统 EVAL 脚本:
-
EVAL脚本是“一次性的表达式”,无注册名、无持久化、无命名空间,靠客户端缓存 SHA1 复用 -
FUNCTION LOAD要求显式声明函数名、入口函数、键/参数约束,且函数一旦加载就持久存在、集群自动同步 - 函数内无法访问
KEYS数组的原始索引语义(如KEYS[1]),必须通过redis.register_function(name, fn)注册的回调函数接收解析后的keys和args参数 - 函数不支持
redis.log()(日志被禁用),也不允许调用redis.sha1hex()等非安全函数
换句话说:你不能把一段 EVAL "return redis.call('GET', KEYS[1])" 1 mykey 直接塞进 FUNCTION LOAD。必须重写为:
FUNCTION LOAD "#!lua name=mylib\nredis.register_function('get_key', function(keys, args) return redis.call('GET', keys[1]) end)"
再用 FCALL get_key 1 mykey 调用——这已是不同抽象层级的编程模型。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
为什么 EVALSHA 在 7.x 集群中更容易失败?
不是“更容易失败”,而是失败原因更明确:7.x 强制要求所有分片节点都预加载过对应脚本 SHA1,否则直接返回 NOSCRIPT;而 6.x 在某些客户端驱动里会静默 fallback 到 EVAL(不推荐,但存在)。7.x 不做任何 fallback,必须由客户端主动捕获 NOSCRIPT 并触发 SCRIPT LOAD + EVAL 重试流程。
常见踩坑点:
- 集群扩容新节点后,忘了运行
SCRIPT LOAD同步全部常用脚本 - 使用
redis-cli --eval测试时,脚本只加载到当前连接的节点,误以为全集群已就绪 - 依赖客户端自动缓存 SHA1,但没处理
NOSCRIPT的重载逻辑,导致偶发失败
建议做法:上线前用 SCRIPT LOAD 批量预热所有核心脚本,并在客户端封装一层带 fallback 的 evalsha_safe 工具函数。
脚本性能在 7.x 有实质提升吗?
单次执行耗时几乎无差别。Lua 解释器没换,核心指令开销一致。真正有变化的是两点:
- 7.x 的
FUNCTION支持预编译字节码并跨节点共享,首次调用后后续FCALL省去解析+校验开销,比反复EVALSHA略快(实测差异通常 - 7.x 默认启用
threaded-io yes,I/O 线程可并行处理网络读写,间接缓解长脚本阻塞主线程时的请求积压(但脚本本身仍在主线程执行)
所以别指望靠升 7.x 让旧脚本“变快”,真正的性能收益来自迁移到 FUNCTION + 合理拆分逻辑 + 控制脚本时长。超过 100 行或含密集循环的 Lua 脚本,在 6.x 和 7.x 下都该重构,而不是升级等待优化。










