Redis 集群批量删除key报错 CROSSSLOT Keys in request don‘t hash to the same slot
Redis 集群报错 CROSSSLOT Keys in request don't hash to the same slot
的原因及解决方案
1. 错误原因
在 Redis 集群模式下,数据根据 哈希槽(Slot) 分散存储在不同的节点上(默认 16384 个槽)。当执行涉及多个 key 的命令(如 DEL key1 key2
、MGET
、MSET
等)时,这些 key 必须属于同一个哈希槽,否则会触发此错误。
示例场景:
# 错误:key1 和 key2 属于不同槽
127.0.0.1:6379> DEL key1 key2
(error) CROSSSLOT Keys in request don't hash to the same slot
2. 根本原因
- Redis 集群要求跨 key 操作的原子性,而不同槽的 key 可能位于不同节点,无法保证原子性。
- 影响命令:
DEL
、MGET
、MSET
、SUNION
等多 key 操作。
3. 解决方案
方案 1:强制所有 key 使用相同哈希槽(推荐)
通过 哈希标签(Hash Tag) 强制让多个 key 分配到同一个槽。
方法:用 {}
包裹 key 的相同部分,Redis 仅根据 {}
内的内容计算槽。
示例:
# 正确:key1 和 key2 使用相同的哈希标签
127.0.0.1:6379> DEL user:{100}:name user:{100}:age
(integer) 2 # 成功删除
方案 2:单 key 操作替代多 key 操作
将批量操作拆分为单个命令:
# 原始错误命令
DEL key1 key2# 改为单 key 操作
DEL key1
DEL key2
方案 3:使用 -c
参数让 redis-cli
自动重定向
在 redis-cli
中启用集群模式(-c
),自动重定向到正确节点:
redis-cli -c -h <host> -p <port> DEL key1 key2
但此方法仍可能因跨槽失败,仅适用于 key 巧合在同一节点的情况。
方案 4:Lua 脚本保证原子性
Lua 脚本在集群中会被整体发送到同一个节点执行:
-- delete_keys.lua
redis.call('DEL', KEYS[1])
redis.call('DEL', KEYS[2])
执行:
redis-cli -h <host> -p <port> --eval delete_keys.lua key1 key2
方案 5:遍历所有节点删除(适用于模糊匹配)
若需删除通配符匹配的 key(如 index_kline*
),需遍历所有节点:
# 获取集群所有主节点
NODES=$(redis-cli -h <host> -p <port> cluster nodes | grep master | awk '{print $2}' | cut -d '@' -f1)# 逐个节点执行 SCAN + DEL
for node in $NODES; doredis-cli -h ${node%:*} -p ${node#*:} --scan --pattern "index_kline*" | xargs -n 100 redis-cli -h ${node%:*} -p ${node#*:} DEL
done
4. 如何避免此问题?
- 设计 key 时使用哈希标签:
例如order:{123}:items
和order:{123}:status
保证相同订单的 key 在同一个槽。 - 避免跨槽的多 key 操作:
优先使用单 key 命令或事务(MULTI
/EXEC
)。 - 查询 key 的槽分布:
redis-cli -h <host> -p <port> CLUSTER KEYSLOT "your_key"
5. 总结
场景 | 解决方案 |
---|---|
批量删除固定 key | 使用哈希标签({} ) |
模糊删除通配符 key | 遍历所有节点 + SCAN |
需要原子性操作 | Lua 脚本 |
临时修复 | 单 key 操作或 -c 模式 |
关键点:Redis 集群的多 key 操作必须满足 同槽规则,设计 key 时提前规划哈希标签可彻底避免此问题。