中 困难
Redis-Cluster槽分配#
一句话答案#
Redis Cluster 将数据分到 16384 个哈希槽,CRC16(key)%16384 定位节点,增减节点只迁移部分槽。
核心要点
Hash Slot 分片机制:
Redis Cluster 将整个数据集划分为 16384 个 slot:
key → CRC16(key) % 16384 → slot 编号 → 落在哪个节点
例:3 主节点的默认分配:
Node A: slot 0 ~ 5460
Node B: slot 5461 ~ 10922
Node C: slot 10923 ~ 16383plaintext为什么是 16384 个 slot(而不是更多)?
① 节点间通过 Gossip 协议交换 slot 信息,每次心跳包携带一个 bitmap
16384 个 slot → bitmap 大小 = 16384 / 8 = 2KB(可接受)
如果用 65536 个 slot → bitmap = 8KB,心跳包过大
② Redis Cluster 推荐最多 1000 个节点
16384 个 slot 平均每个节点约 16 个 slot,足够均匀
③ 作者 Antirez 认为 16384 在工程上是最佳平衡点plaintextHash Tag(强制相关 key 落同一 slot):
# 大括号 {} 内的部分参与 hash 计算
SET {user:1001}:info "Alice"
SET {user:1001}:cart "..."
# 两个 key 都按 "user:1001" 计算 slot → 落在同一节点
# 保证 MGET、Pipeline、Lua 脚本可以操作这些 keybashSlot 迁移的详细过程(单个 slot):
将 slot X 从 Node A 迁移到 Node D:
1. Node D: CLUSTER SETSLOT X IMPORTING <A的nodeId>
→ D 准备导入 slot X 的数据
2. Node A: CLUSTER SETSLOT X MIGRATING <D的nodeId>
→ A 将 slot X 标记为迁移中
3. 循环迁移 key:
① CLUSTER GETKEYSINSLOT X 100 # 从 A 获取 slot X 中的 100 个 key
② MIGRATE <D的ip> <D的port> "" 0 5000 KEYS key1 key2 ... # 原子迁移到 D
③ 重复直到该 slot 的所有 key 迁移完毕
4. 通知所有节点 slot X 现在属于 D:
CLUSTER SETSLOT X NODE <D的nodeId> # 向所有节点广播plaintext扩容与缩容:
扩容(添加新节点 + 分配 slot):
1. redis-cli --cluster add-node <新节点> <集群节点>
2. redis-cli --cluster reshard <集群节点> → 从已有节点迁出部分 slot
3. 为新主节点添加从节点(--cluster-slave)
缩容(移除节点):
1. 将待移除节点的 slot 迁移到其他节点(resharding)
2. redis-cli --cluster del-node <集群节点> <待移除节点ID>
3. 主节点的从节点会自动挂到其他主节点下plaintextMOVED vs ASK 重定向:
| 类型 | 含义 | 客户端行为 |
|---|---|---|
| MOVED | slot 已永久迁移到新节点 | 更新本地路由表,后续直接访问新节点 |
| ASK | slot 正在迁移中,该 key 已迁走 | 仅本次临时访问新节点,不更新路由表 |
面试回答(2分钟版)
Redis Cluster 采用哈希槽分片机制,将整个数据集划分为 16384 个 slot,每个 key 通过 CRC16(key) % 16384 计算得到 slot 编号,再根据 slot 到节点的映射关系定位数据所在节点。选择 16384 个槽是工程上的平衡:每个节点通过 Gossip 协议交换 slot 位图信息,16384 位只需 2KB,心跳包大小可接受。故障检测分两个阶段:节点 A 对 B 发 PING 超时后本地标记为 PFAIL,通过 Gossip 传播后当超过半数主节点都认为 B 疑似下线时标记为 FAIL 并触发故障转移。从节点选举时复制偏移量最大的从节点优先当选,获得半数以上主节点投票后执行 SLAVEOF NO ONE 接管 slot。扩容时通过 reshard 从已有节点迁移部分 slot 到新节点,迁移期间客户端访问已迁移的 key 会收到 ASK 重定向,迁移完成后收到 MOVED 重定向更新本地路由表。
追问与易错
追问方向:
- “Cluster 怎么处理热点 Key?”→ Cluster 本身不解决热点,需应用层处理:本地缓存(Caffeine)减少 Redis 访问、Key 加随机后缀打散到多个 slot、读副本分担读请求
- “MOVED 和 ASK 重定向区别?”→ MOVED 表示 slot 已永久迁移到新节点,客户端应更新本地路由表后续直接访问新节点;ASK 表示 slot 正在迁移中该 key 已迁走,客户端仅本次临时访问新节点,不更新路由表
- “怎么扩容节点?”→ 先用 redis-cli —cluster add-node 将新节点加入集群,再用 reshard 从现有节点迁移部分 slot 到新节点,最后为新主节点添加从节点保证高可用
易错点:
- ❌ Cluster 自动解决热点——需应用层处理
- ❌ 混淆 MOVED 和 ASK