Redis 中的 槽(Slot) 和 跨槽(Cross-slot) 是 Redis 集群(Cluster)模式中的核心概念,直接关系到数据分布和操作限制。以下是通俗解释和实际案例:
一、槽(Slot)是什么?
-
基本定义
- Redis 集群将所有数据划分为 16384 个槽(固定数量),每个槽是一个逻辑存储单元。
- 每个键(Key)通过 CRC16 哈希算法计算后,会分配到其中一个槽:
slot = CRC16(key) % 16384
- 集群中的每个节点(Node)负责管理一部分槽(例如 Node1 管理 0-5000 槽,Node2 管理 5001-10000 槽)。
-
为什么需要槽?
- 数据分片:将海量数据分散到多个节点,突破单机内存限制。
- 负载均衡:自动平衡各节点的数据量和请求压力。
- 故障转移:某个节点故障时,其负责的槽会被转移到其他正常节点。
二、跨槽(Cross-slot)操作是什么?
定义
跨槽操作是指一条 Redis 命令涉及多个键,但这些键被分配到不同的槽中。Redis 集群默认 禁止跨槽操作,因为不同槽可能位于不同节点,无法保证原子性。
典型报错
(error) CROSSSLOT Keys in request don't hash to the same slot
三、跨槽场景与解决方案
场景1:批量操作多个键
❌ 错误操作(跨槽报错)
# 尝试用 MGET 获取多个不同槽的键
MGET user:10001:name user:10002:name
✅ 解决方案
-
使用 Hash Tag 强制分配到同一槽
在键中添加{}
包裹的相同内容,强制哈希到同一槽:# 添加 {user} 作为 Hash Tag MGET {user}:10001:name {user}:10002:name
- 此时 CRC16 计算仅基于
user
,确保两个键分配到同一槽。
- 此时 CRC16 计算仅基于
-
改用 Pipeline 分批次请求
如果无法修改键,客户端需将请求拆分成多个单键操作,通过 Pipeline 批量发送。
场景2:事务(MULTI)操作
❌ 错误操作(跨槽报错)
# 事务中包含不同槽的键
MULTI
SET {user}:10001:name "John"
SET {order}:20001:status "paid"
EXEC
✅ 解决方案
所有事务中的键必须使用 相同的 Hash Tag:
# 统一使用 {user10001} 作为 Hash Tag
MULTI
SET {user10001}:name "John"
SET {user10001}:order:20001:status "paid"
EXEC
四、如何查看键所在的槽?
-
使用
CLUSTER KEYSLOT
命令CLUSTER KEYSLOT "user:10001:name"
- 返回结果示例:
(integer) 12706
(表示该键属于 12706 号槽)。
- 返回结果示例:
-
查看集群槽分布
CLUSTER SLOTS
- 输出结果示例:
1) 1) 0 # 起始槽 2) 5460 # 结束槽 3) 127.0.0.1:7001 # 主节点 4) 127.0.0.1:7002 # 从节点
- 输出结果示例:
五、跨槽操作总结
操作类型 | 是否允许跨槽 | 解决方案 |
---|---|---|
单键操作 | ✅ 允许 | 无需处理 |
多键操作 | ❌ 禁止 | Hash Tag、Pipeline 分批 |
事务(MULTI) | ❌ 禁止 | 所有键使用相同 Hash Tag |
Lua 脚本 | ❌ 禁止 | 所有键使用相同 Hash Tag |
六、最佳实践
- 设计键时提前规划 Hash Tag
- 示例:
{user:10001}:profile
、{user:10001}:orders
- 示例:
- 避免全局遍历操作
KEYS *
、SCAN
等命令在集群中需遍历所有节点,性能极差。
- 跨槽操作的替代方案
- 如果必须跨槽聚合数据,可在客户端先分散查询,再合并结果。
通过合理使用 Hash Tag 和规避跨槽操作,可以充分发挥 Redis 集群的分布式优势,同时避免操作限制带来的问题。