redis集群禁止跨slot执行lua脚本是设计使然,报crossslot错误发生在服务端入口校验阶段,所有keys必须同槽;哈希标签{xxx}强制仅括号内内容参与crc16计算,是唯一官方支持的同槽方案。

Redis集群模式下Lua脚本根本不是“不支持”,而是明确禁止跨slot执行——报CROSSSLOT错误是设计使然,不是bug或配置缺失。
为什么EVAL会直接报CROSSSLOT而不是重定向
Redis集群把16384个slot分给不同节点,每个节点只管自己负责的slot。Lua脚本执行前,Redis会检查所有KEYS参数计算出的slot是否一致;只要有一个不同,就立刻拒绝,连路由转发都不做。这不是客户端没处理好重定向,是服务端在入口就拦截了。
- 报错信息固定为:
CROSSSLOT Keys in request don't hash to the same slot -
redis.call()里拼接的新key(比如"temp:"..KEYS[1])不会被校验,但运行时会触发非本地key访问,报ERR Lua script attempted to access a non-local key - 哪怕两个key只差一个字符(如
user:1001和user:1002),CRC16哈希后大概率落在不同slot,纯靠ID连续无法保证同槽
哈希标签{xxx}怎么写才真正生效
花括号不是装饰,是Redis解析key时的硬规则:只取第一个合法的{}对里的内容参与CRC16计算,其余全部忽略。写错括号位置或嵌套,结果就不可控。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 正确:
user:{1001}:profile→ 哈希1001;order:{1001}:items→ 同样哈希1001,必然同slot - 错误:
user:1001:profile→ 哈希整个字符串,和order:1001:items基本不同slot - 危险:
user{1001}:profile→ 没有闭合{},退化为全字符串哈希;user:{abc{def}:xyz→ 取最内层{def},但容易误读 - 空括号
{}或user:{}:profile→ 视为无效,仍哈希全长
SCRIPT LOAD / EVALSHA在集群里能用吗
能用,但和EVAL受同样限制:SCRIPT LOAD只存脚本,不校验key;真正执行EVALSHA时,仍会检查所有KEYS是否同slot。它只是省了传输脚本体的开销,没绕过slot约束。
- 高频调用场景推荐用
EVALSHA,减少网络包大小 - 客户端必须确保
SCRIPT LOAD和后续EVALSHA传入的KEYS完全一致,否则可能命中缓存但执行失败 - Redis 7.0.11新增的
allow-cross-slot-keys配置仅影响单命令(如MGET),对EVAL和EVALSHA无效
最容易被忽略的坑:客户端没开启ASKING模式
当key带哈希标签且目标slot正在迁移中,节点会返回ASK重定向而非MOVED。此时客户端必须先发ASKING命令,再执行脚本,否则会被拒绝。主流客户端(Lettuce ≥6.1、Jedis ≥3.0)默认处理,但老版本或自研客户端常漏掉这步。
- 现象:脚本偶发失败,日志出现
ASK响应但无后续ASKING - 验证方法:用
redis-cli -c连集群,手动执行带{tag}的EVAL,观察是否自动补ASKING - 如果用管道(pipeline)批量发多个
EVAL,每个都得单独处理ASK流程,不能共用一次ASKING










