必须用{}哈希标签使所有keys按相同字符串计算槽位,因redis集群要求脚本中所有keys必须落在同一slot,否则客户端预检即报crossslot错误,连脚本都不解析;{}仅取首对花括号内内容做crc16,如user:{1001}:a和cart:{1001}:b均按“1001”计算,必然同槽。

关键就一点:用 {} 哈希标签,让所有涉及的 key 都按相同字符串计算槽位。
为什么必须同槽
Redis 集群把 16384 个槽分给不同节点,Lua 脚本执行前,客户端会检查 KEYS 数组里每个 key 的槽位。只要有一个不同,就直接报 CROSSSLOT 错误,连脚本都不解析。这不是 Lua 写得不对,是 key 分布没对齐集群规则。
怎么用 {} 控制槽位
Redis 只取第一个完整 {} 对里的内容做 CRC16 计算,其余部分忽略。所以:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- ✅ 正确示例:
user:{1001}:profile、cart:{1001}:items、order:{1001}:log→ 都按1001算槽,必然同节点 - ❌ 错误示例:
user:1001:profile、order:1001:log→ 整个字符串参与哈希,几乎不可能同槽 - ⚠️ 注意细节:
user:{abc{def}:xyz取的是def;user:{}:profile因为空,退化为整个 key 参与哈希
脚本调用时的硬性要求
Lua 脚本本身不决定槽位,真正起作用的是你传进 KEYS 数组的那些 key:
- 所有要操作的 key 必须显式传入
KEYS,不能在脚本里拼接(比如KEYS[1] .. ":counter")——运行时可能触发MOVED或NOAUTH -
EVALSHA和EVAL校验逻辑完全一致,不是绕过方案,只是减少网络传输 - 客户端(如 Jedis、Lettuce)会在发命令前自动校验 slot,不一致就抛异常,不会发到服务端
上线前必须验证
光靠命名规则不够,扩容或 rehash 后可能失效:
- 用
redis-cli --cluster check <host>:<port></port></host>查看实际槽分布 - 手动测试:对两个带相同 {} 的 key,分别执行
CLUSTER KEYSLOT key1和CLUSTER KEYSLOT key2,确认返回值一致 - 避免在脚本里依赖 value 中的 ID 动态构造 key——写入时就要保证 key 带正确 tag










