欢迎光临
我们一直在努力

Redis分片集群插槽原理

一、前言:为什么 Redis Cluster 不用一致性哈希?

很多分布式系统(如 Memcached)采用一致性哈希实现数据分片,但 Redis Cluster 却另辟蹊径,选择了 “固定数量插槽 + 哈希取模” 的方案。

你是否曾疑惑:

  • 为什么是 16384 个插槽,不是 1024 或 65536?
  • key 是怎么决定去哪个节点的?
  • 为什么 MGET key1 key2 有时会报错?

本文将带你彻底搞懂 Redis 插槽(Slot)机制的设计思想与工作原理。


二、插槽:Redis Cluster 的分片单元

2.1 核心概念

Redis Cluster 将整个键空间划分为 16384 个逻辑插槽(slot),编号从 0 到 16383。

  • 每个 key 通过公式映射到一个 slot:

    slot = CRC16(key) % 16384

  • 每个 master 节点负责一部分插槽(可以不连续)
  • 客户端根据 slot 路由请求到对应节点

✅ 优势:

  • 分片规则简单、确定
  • 扩容时只需迁移部分 slot,无需 rehash 全量数据
  • 节点增减对客户端透明(自动重定向)

三、为什么是 16384?深度解析设计权衡

这是 Redis 作者 antirez 在 GitHub 上亲自回答的经典问题。

3.1 官方解释(精简)

“16384 是在消息大小、集群规模和内存开销之间取得的最佳平衡。”

3.2 技术细节分析

插槽数每节点心跳包大小支持最大节点数内存开销(每节点)
65536 ~130 KB < 100 128 KB
16384 ~32 KB ~1000 32 KB
4096 ~8 KB > 1000 8 KB
🔍 关键原因:
  • 心跳包不能太大
    Redis 节点每秒通过 gossip 协议广播集群状态,包含每个 slot 的归属。
    若 slot 太多(如 65536),心跳包过大,浪费带宽。

  • slot 不能太少
    若只有 1024 个 slot,当集群有 100 个节点时,平均每个节点仅 10 个 slot,负载极不均衡。

  • 16384 = 2^14

    • 足够大:支持千级节点(实际生产建议 ≤ 100)
    • 足够小:心跳包控制在 32KB 以内
    • 内存友好:每个 slot 状态占 2 字节 → 总计 32KB
  • 💡 结论:16384 不是魔法数字,而是工程实践中的最优解。


    四、Key 到插槽的计算流程

    4.1 标准计算公式

    slot = CRC16(key) % 16384

    4.2 特殊情况:Hash Tag(哈希标签)

    Redis 支持通过 {} 强制多个 key 落在同一插槽:

    • user:{1001}:name → 取 {1001} 计算 slot
    • user:{1001}:age → 同样取 {1001} → 相同 slot

    ✅ 用途:解决 multi-key 操作跨 slot 问题(如 MGET, SUNION)

    4.3 Java 示例:计算 key 所属插槽

    public static int calculateSlot(String key) {
    // 1. 提取 Hash Tag
    String hashTag = key;
    int start = key.indexOf('{');
    if (start != -1) {
    int end = key.indexOf('}', start + 1);
    if (end != -1 && end > start + 1) {
    hashTag = key.substring(start + 1, end);
    }
    }

    // 2. CRC16 计算(使用标准实现)
    int crc = CRC16.crc16(hashTag.getBytes(StandardCharsets.UTF_8));

    // 3. 取模
    return crc % 16384;
    }


    五、客户端如何找到 key 所在节点?

    5.1 首次访问:MOVED 重定向

  • 客户端随机连一个节点(如 7001)
  • 节点计算 key 的 slot,发现不在自己负责范围
  • 返回错误:

    MOVED 5461 192.168.1.10:7002

  • 客户端缓存 <slot → node> 映射,并重连 7002
  • 5.2 扩容迁移中:ASK 重定向

    当 slot 正在迁移:

    • 源节点返回 ASK 5461 192.168.1.10:7003
    • 客户端先发 ASKING 命令,再发原命令

    ✅ Lettuce / Jedis Cluster 客户端自动处理这些重定向,业务代码无感知。


    六、为什么多 key 操作会失败?

    6.1 错误示例

    redis-cli -c MGET user:1 order:1
    # (error) CROSSSLOT Keys in request don't hash to the same slot

    6.2 原因

    Redis Cluster 要求所有 key 必须在同一插槽,否则无法保证原子性。

    6.3 解决方案:使用 Hash Tag

    # 强制落在同一插槽
    MGET {user100}.profile {user100}.settings # ✅ 成功

    📌 最佳实践:对需要批量操作的数据,使用相同 Hash Tag 前缀。


    七、插槽迁移与集群扩缩容

    7.1 扩容流程(新增 master)

  • 新节点加入集群(CLUSTER MEET)
  • 从现有节点迁移部分插槽到新节点
  • 客户端通过 MOVED/ASK 自动重定向
  • 迁移完成后,集群负载更均衡
  • 7.2 迁移命令(底层)

    # 源节点执行:迁移 key
    MIGRATE 192.168.1.11 7004 "" 0 5000 KEYS key1 key2

    # 更新插槽归属
    CLUSTER SETSLOT 5461 NODE <new-node-id>

    ⚠️ 注意:迁移过程无需停机,客户端可能短暂收到 ASK。


    八、常用运维命令

    命令作用
    CLUSTER SLOTS 查看所有插槽分配情况
    CLUSTER KEYSLOT key 查询 key 所属插槽
    CLUSTER COUNTKEYSINSLOT 5461 统计某插槽 key 数量
    CLUSTER GETKEYSINSLOT 5461 10 获取某插槽的 10 个 key

    九、结语

    感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

    赞(0)
    未经允许不得转载:171主机测评 » Redis分片集群插槽原理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址