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 時提前規劃哈希標簽可徹底避免此問題。