Redis 6.2 强制启用 lua-replicate-commands yes,将 Lua 脚本拆解为确定性原子命令同步,避免非确定性命令(如 TIME)导致主从不一致;若设为 no,则主节点直接拒绝执行脚本。

Redis 6.2 并没有引入“新的脚本同步策略”——它沿用的是 EVAL 和 EVALSHA 的原有传播机制,但首次强制要求:所有执行 Lua 脚本的节点必须启用 lua-replicate-commands yes(默认开启),否则脚本将被拒绝执行。
为什么 lua-replicate-commands 成为关键开关
在 Redis 6.2 之前,Lua 脚本默认以“整个脚本体”形式同步到从节点(即 REPLCONF 发送 EVAL 命令字符串)。这种方式简单,但有严重隐患:
- 主从脚本执行结果可能不一致(比如脚本里用了
TIME、RANDOMKEY等非确定性命令) - 从节点重放脚本时若出错(如 key 类型不匹配),无法定位是哪条子操作失败
- 大脚本在网络传输和从节点解析阶段都更耗资源
而 lua-replicate-commands yes 改变了行为:Redis 运行时会把脚本拆解成一系列确定性的原子命令(如 SET、INCR、HSET),只把这些命令同步过去,跳过脚本本身。这依赖两个前提:
- 脚本内所有操作必须是「纯数据操作」且可预测(不能含
redis.call("TIME")) - 主从节点的 Lua 环境必须完全一致(比如都禁用
math.random)
EVALSHA 在 6.2 下为何更敏感
即使你用 EVALSHA 触发已缓存的脚本,只要 lua-replicate-commands 开启,Redis 仍会走命令拆解路径——不是复用 SHA 后直接执行,而是重新解析脚本体、提取子命令再传播。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
这意味着:
- 如果脚本里混了
redis.pcall("KEYS", "*")这类禁止命令,主节点能跑通,但从节点同步时会报ERR Error running script -
SCRIPT LOAD不再保证“加载即可用”,因为真正校验发生在首次执行+同步阶段 - 监控
slowlog时,看到的可能是SET或ZADD,而不是EVALSHA—— 因为传播的是子命令
升级到 6.2 后最常踩的坑
很多团队在迁移后遇到复制中断或从节点报错,根本原因往往是:
- 旧脚本里用了
redis.call("DEBUG", "RELOAD")或os.time()—— 这些在 6.2+ 默认被拦截 - 配置里显式写了
lua-replicate-commands no,导致主节点拒绝执行任何脚本(错误信息:ERR Lua scripts are disabled because lua-replicate-commands is set to 'no') - 集群环境下,某个分片开启了该选项,另一个没开,造成主从命令流不一致,触发
NOAUTH或WRONGTYPE异常
验证方式很简单:连上实例执行 CONFIG GET lua-replicate-commands,确认返回 yes;再用 SCRIPT DEBUG YES 开启调试,观察 SLOWLOG GET 是否出现子命令条目。
真正容易被忽略的是:这个开关不是“功能增强”,而是“一致性加固”。它让脚本从“黑盒执行单元”退回到“可审计、可拆解、可对齐的命令序列”。一旦你依赖了非确定性行为,6.2 就会立刻暴露问题——不是它变严格了,是你之前没意识到脚本同步本来就不该这么用。

















