Redis 集群数据分片

面试官问:"Redis Cluster 是怎么做数据分片的?"

小陈说:"用 slot。"

面试官追问:"16384 个 slot 是怎么映射到 key 的?"

小陈说:"...取模?"

面试官继续追问:"为什么是 16384 而不是 65536?"

小陈答不上来。

Hash Slot 是 Redis Cluster 数据分片的核心。这道题能说清楚 CRC16 算法和 Key Tag 技巧的候选人,对 Redis Cluster 的数据分片有深入理解。

一、Slot 映射原理 🔴

1.1 CRC16 算法

# Redis Cluster 使用 CRC16 计算 slot
import binascii

def crc16(key):
    """CRC16 算法,Redis 使用的多项式是 0x8005"""
    crc = 0
    for byte in key.encode('utf-8'):
        crc = (crc >> 8) ^ crc16_table[(crc ^ byte) & 0xff]
    return crc

def slot(key):
    """计算 key 所属的 slot"""
    return crc16(key) & 0x3FFF  # 16384 - 1 = 0x3FFF

# 示例:
slot("user:100")    # CRC16("user:100") = 12345 % 16384 = 12345
slot("product:200") # CRC16("product:200") = 54321 % 16384 = 54321

1.2 为什么是 16384?

-- 选择 16384 的原因:
-- 1. 槽信息大小:
--    - 16384 个 slot = 16384 bits = 2KB
--    - 65536 个 slot = 65536 bits = 8KB
-- 2. Gossip 协议传播:
--    - 每个节点需要广播自己的槽信息
--    - 节点越多,广播越频繁
--    - 2KB 比 8KB 更轻量

-- 选择 16384 的权衡:
-- 1. 如果集群小于 1000 个节点,16384 足够
-- 2. 每个主节点平均分配 ~5460 个 slot
-- 3. 如果需要更多节点,可以增加 slot 数量
-- 4. 但增加意味着更大的槽信息开销

1.3 ❌ 错误示范

候选人原话:"用哈希算法把 key 分到不同 slot。"

问题诊断:不精确。Redis Cluster 用的是 CRC16,不是普通的哈希算法。CRC16 的分布更均匀,且结果在固定范围内。

【面试官心理】 这道题我会追问"为什么不用 MD5 或 SHA1"。能说清楚 CRC16 的优势和 16384 的权衡的候选人,说明他对 Cluster 的设计有深入理解。

二、Key Tag 技巧 🟡

2.1 问题

-- 场景:想保证多个相关的 key 在同一个 slot
-- keys: order:user:100:info, order:user:100:items, order:user:100:payment

slot("order:user:100:info")    = 5432
slot("order:user:100:items")    = 9876  # 不同 slot!
slot("order:user:100:payment")  = 3210  # 不同 slot!

-- 问题:这些 key 在不同 slot,无法用 MGET/ Pipeline

2.2 Key Tag 解决方案

-- Key Tag:用 {} 包裹业务 key,Redis 只对 {} 内的内容计算 slot

slot("order:{user:100}:info")    = CRC16("user:100") = 1234
slot("order:{user:100}:items")   = CRC16("user:100") = 1234  # 同一 slot!
slot("order:{user:100}:payment") = CRC16("user:100") = 1234  # 同一 slot!

-- 示例:
MGET order:{user:100}:info order:{user:100}:items
-- 可以正常执行(在同一节点)

2.3 Key Tag 的限制

-- Key Tag 规则:
-- 1. 只有第一个 {} 内的内容参与 slot 计算
-- 2. 如果没有 {},整个 key 参与计算
-- 3. 如果有多个 {},只取第一个

slot("a{x}b{x}c") = slot("x")
slot("x") = slot("a{x}b{x}c")

三、槽迁移 🟡

3.1 在线槽迁移

# Redis 5.0+ 的 redis-cli 槽迁移
redis-cli --cluster reshard 任意节点:端口

# 选择迁移的槽数量
# 选择目标节点
# 选择源节点

# 或者命令式迁移
redis-cli --cluster setslot 12345 importing 目标节点ID
redis-cli --cluster setslot 12345 migrating 源节点ID

3.2 迁移过程中的访问

-- slot 迁移中,其他 key 的访问:
-- 1. 如果 key 在源节点:返回数据
-- 2. 如果 key 在目标节点:返回 ASK 重定向

GET "order:user:100:info"
# 如果 slot=12345 在迁移中
# 源节点返回: ASK 12345 目标节点:端口

-- 客户端收到 ASK 后:
-- 1. 转向目标节点
-- 2. 发送 ASKING 命令
-- 3. GET key

四、槽统计 🟡

4.1 查看槽分布

redis-cli cluster nodes
# 列出所有节点及其负责的槽

redis-cli cluster slots
# 列出每个槽的范围和对应节点

4.2 均衡性监控

# 检查槽分布是否均衡
redis-cli --cluster info 节点:端口

# 输出示例:
# Cluster Size: 3
# Slots assignment: 节点A:5461, 节点B:5461, 节点C:5462
# (每个节点约 5461 个槽,接近均衡)

【面试官心理】 Hash Slot 是 Redis Cluster 的核心概念。能说清楚 CRC16 算法、Key Tag、16384 数量选择原因的候选人,说明他对 Redis Cluster 有源码级别的理解。


级别考察重点期望回答
P5基本原理CRC16 取模分配 slot
P6深入机制Key Tag、16384 选择原因
P7运维能力槽迁移、ASK vs MOVED