集群数据分布定位

集群数据分布定位

数据在 Redis Cluster 中如何存放

Redis Cluster 不使用传统的一致性哈希算法,而是采用哈希槽 + 虚拟槽映射表的方案。整个数据定位流程分为三步:计算哈希槽 → 查找槽归属 → 定位物理节点

三步定位法

第一步:计算 Key 的哈希槽

slot_id = CRC16(key) % 16384

CRC16 是一种高效的循环冗余校验算法。Redis 对其做了特殊处理——如果 Key 中包含 {...} 格式的大括号,则只对大括号内的内容计算哈希(即 Hash Tag 机制)。

第二步:查找槽所属节点

每个节点都维护着一份集群状态信息,其中包含一个长度为 16384 的槽位数组(slots array),记录了每个槽由哪个节点负责。

slot 0    → 节点 A (node-id: abc123)
slot 1    → 节点 A
...
slot 5461 → 节点 B (node-id: def456)
...
slot 16383 → 节点 C (node-id: ghi789)

第三步:路由到目标节点

客户端侧路由(Smart Client)
大多数 Redis 客户端(如 JedisCluster、Lettuce、redis-py-cluster)实现了智能路由。它们:
1. 连接集群中的任意节点
2. 通过 CLUSTER SLOTSCLUSTER NODES 命令获取完整的槽-节点映射表
3. 在本地缓存这份映射表
4. 直接计算 Key 的槽位,然后连接到目标节点

如果客户端缓存过时(比如发生了槽迁移),节点会返回 MOVED 错误,客户端更新缓存后重试。

槽位信息的传播

初始化阶段

当节点加入集群时:
1. 空节点加入集群(通过 CLUSTER MEET
2. 主节点分配槽位(通过 CLUSTER ADDSLOTS
3. 节点将自己的槽位信息广播给集群中其他节点
4. 其他节点更新本地槽位映射

运行阶段

节点之间通过 Gossip 协议定期交换信息。每个 PING/PONG 消息中都包含发送节点的槽位位图(2048 字节的 bit array),标记哪些槽属于自己。

节点内部数据结构

每个 Redis Cluster 节点内部维护着两个关键的槽位数组:

clusterState.slots[16384]

这是一个数组,每个元素指向一个 clusterNode 结构体。通过槽位号可以直接 O(1) 找到负责该槽的节点。

// 伪代码
clusterNode *slots[16384];
// slots[7256] = &nodeB;  // 槽 7256 由节点 B 负责

clusterNode.slot_info[]

每个节点自身维护一个位图,记录自己负责哪些槽。这个位图在 Gossip 消息中传播。

MOVED 与 ASK 重定向

MOVED 重定向(永久)

-MOVED 7256 192.168.1.3:6379

含义:槽 7256 已经永久迁移到了 192.168.1.3:6379。客户端应该立即更新本地缓存,后续所有属于槽 7256 的 Key 都直接发往新节点。

ASK 重定向(临时)

-ASK 7256 192.168.1.3:6379

含义:槽 7256 正在迁移过程中,该 Key 可能已经迁移到了目标节点。客户端需要先向目标节点发 ASKING 命令,然后再发原命令。ASK 只是临时一次性行为,不会更新客户端本地缓存。

对比一致性哈希

特性 哈希槽方案 一致性哈希
虚拟节点数 固定 16384 可配置
数据分布均匀性 好(槽数远大于节点数) 依赖虚拟节点配置
增删节点影响 只影响被迁移的槽 只影响相邻节点
实现复杂度 较简单 较复杂
客户端要求 必须支持智能路由 需要哈希环

总结

Redis Cluster 的数据定位采用了”计算槽→查映射→找节点“的三步方式。客户端通过缓存完整的槽位映射表实现高效路由,节点通过 Gossip 协议保持映射表的一致性。MOVED 和 ASK 两种重定向策略分别处理了稳态和迁移态的路由问题,保证了集群在动态变化中的数据可达性。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容