面试知识库
困难

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 ~ 16383
plaintext

为什么是 16384 个 slot(而不是更多)?

① 节点间通过 Gossip 协议交换 slot 信息,每次心跳包携带一个 bitmap
   16384 个 slot → bitmap 大小 = 16384 / 8 = 2KB(可接受)
   如果用 65536 个 slot → bitmap = 8KB,心跳包过大

② Redis Cluster 推荐最多 1000 个节点
   16384 个 slot 平均每个节点约 16 个 slot,足够均匀

③ 作者 Antirez 认为 16384 在工程上是最佳平衡点
plaintext

Hash Tag(强制相关 key 落同一 slot):

# 大括号 {} 内的部分参与 hash 计算
SET {user:1001}:info "Alice"
SET {user:1001}:cart "..."
# 两个 key 都按 "user:1001" 计算 slot → 落在同一节点
# 保证 MGET、Pipeline、Lua 脚本可以操作这些 key
bash

Slot 迁移的详细过程(单个 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. 主节点的从节点会自动挂到其他主节点下
plaintext

MOVED vs ASK 重定向:

类型含义客户端行为
MOVEDslot 已永久迁移到新节点更新本地路由表,后续直接访问新节点
ASKslot 正在迁移中,该 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