Redis分片集群插槽原理

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

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

你是否曾疑惑:

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

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


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

2.1 核心概念

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

  • 每个 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
🔍 关键原因:
  1. 心跳包不能太大

    Redis 节点每秒通过 gossip 协议广播集群状态,包含每个 slot 的归属。

    若 slot 太多(如 65536),心跳包过大,浪费带宽。

  2. slot 不能太少

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

  3. 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 所属插槽

java 复制代码
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 重定向

  1. 客户端随机连一个节点(如 7001)

  2. 节点计算 key 的 slot,发现不在自己负责范围

  3. 返回错误:

    复制代码
    MOVED 5461 192.168.1.10:7002
  4. 客户端缓存 <slot → node> 映射,并重连 7002

5.2 扩容迁移中:ASK 重定向

当 slot 正在迁移:

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

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


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

6.1 错误示例

bash 复制代码
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

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

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


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

7.1 扩容流程(新增 master)

  1. 新节点加入集群(CLUSTER MEET
  2. 从现有节点迁移部分插槽到新节点
  3. 客户端通过 MOVED/ASK 自动重定向
  4. 迁移完成后,集群负载更均衡

7.2 迁移命令(底层)

bash 复制代码
# 源节点执行:迁移 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

九、结语

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

相关推荐
冷小鱼2 小时前
pgvector 向量数据库完全指南:PostgreSQL 生态的 AI 增强
数据库·人工智能·postgresql
陈天伟教授2 小时前
人工智能应用- 天文学家的助手:08. 星系定位与分类
前端·javascript·数据库·人工智能·机器学习
yunyun321232 小时前
用Python生成艺术:分形与算法绘图
jvm·数据库·python
ノBye~2 小时前
Centos7.6 Docker安装redis(带密码 + 持久化)
java·redis·docker
m0_662577972 小时前
高级爬虫技巧:处理JavaScript渲染(Selenium)
jvm·数据库·python
ℳ๓₯㎕.空城旧梦3 小时前
Python单元测试(unittest)实战指南
jvm·数据库·python
Navicat中国3 小时前
Navicat 高效破解 SQL 编写繁琐难题,提升数据库设计效率
数据库·可视化·sql编写繁琐
Amctwd3 小时前
【数据库】常用 Sql 示例
数据库·sql·oracle
知识分享小能手4 小时前
Redis入门学习教程,从入门到精通,Redis 数据操作:知识点详解与代码实战(2)
数据库·redis·学习