Redis集群要求Lua脚本中key必须直接使用KEYS[1]等字面量形式,因slot校验在执行前静态分析,不识别变量或ARGV;否则报错ERR bad lua script。
KEYS[1] 而不能赋值给变量再用因为 Redis 集群在执行脚本前,要静态分析所有被操作的 key 所属 slot,确保它们落在同一个分片上。这个分析只认字面量形式的 KEYS[n](比如 KEYS[1]、KEYS[2]),不识别任何中间变量或表达式。
一旦你写 local k = KEYS[1]; redis.call("GET", k),Redis 就无法在解析阶段确认 k 指向哪个 key,也就无法校验 slot 一致性——直接拒绝执行,报错 ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array。
KEYS 数组里放错一个 key 就会报 ERR eval/evalsha command keys must in same slot
集群要求所有 KEYS 中的 key 必须属于同一个 slot,否则脚本连解析都过不去。Redis 用 CRC16(key) % 16384 算 slot,看似随机,但实际结果可预测。
user:1001 和 user:1002 一定同 slot —— 它们 hash 后很可能落在不同分片{tag} 方式强制对齐 slot,例如 user:{1001}:profile 和 user:{1001}:settings(花括号内相同)redis-cli --cluster check 或 CLUSTER KEYSLOT <key> 可验证 slot 分布ARGV 不能当 key 用,哪怕它传的是字符串ARGV 是纯数据容器,Redis 明确禁止在 redis.call() 的 key 参数位置使用 ARGV[n]。哪怕 ARGV[1] 的值是 "mykey",写成 redis.call("GET", ARGV[1]) 也会触发 ERR bad lua script。
KEYS 的值塞进了 ARGV
KEYS 内容),且脚本里只能以 KEYS[1] 形式硬引用KEYS/ARGV 映射就全乱EVAL 命令结构是:EVAL <script> <numkeys> <key1> <key2> ... <arg1> <arg2> ...。其中 numkeys 是整数,决定了前几个参数进 KEYS,剩下的全进 ARGV。
EVAL "return KEYS[1]" 1 mykey hello → KEYS[1] == "mykey",ARGV[1] == "hello"
EVAL "return KEYS[1]" 0 mykey hello → KEYS 为空,ARGV[1] == "mykey",ARGV[2] == "hello",脚本访问 KEYS[1] 就报 attempt to index a nil value
最易被忽略的一点:slot 校验发生在脚本加载前,和 Lua 逻辑是否执行无关。哪怕你脚本里 if false then redis.call("GET", KEYS[1]) end,只要语法上出现了 KEYS[1],Redis 就会去查它所属 slot —— 所以“绕过检查”的尝试注定失败。