面试题:在 Redis 集群中,如何根据键定位到对应的节点?

在 Redis 集群中,键的定位是通过 哈希槽(Hash Slot) 机制实现的。以下是完整的定位流程和关键设计点:


1. 哈希槽(Hash Slot)的基本概念

  • 哈希槽数量:Redis 集群将键空间划分为 16384 个哈希槽(0~16383)。
  • 键与槽的映射:每个键通过 CRC16 算法计算哈希值,并对 16384 取模,确定所属的槽:
  hash_slot = CRC16(key) % 16384

例如,键 user:1000 的 CRC16 哈希值为 12345,则其所属槽为 12345 % 16384 = 12345


2. 槽到节点的映射

  • 节点负责槽:集群中的每个节点负责一部分哈希槽。例如:
    • 节点 A:槽 0~5460
    • 节点 B:槽 5461~10922
    • 节点 C:槽 10923~16383
  • 槽分布动态调整:当集群扩容或缩容时,槽会重新分配(通过 CLUSTER REBALANCE 命令),节点之间通过 Gossip 协议同步槽的归属信息。

3. 客户端如何定位键所在的节点

(1) 客户端视角的流程

  1. 计算哈希槽:客户端根据键名计算哈希槽。
  2. 查询槽映射表:客户端维护一个本地的 槽到节点的映射表(通过 CLUSTER SLOTS 命令获取或缓存 MOVED 错误更新)。
  3. 发送请求到对应节点:根据槽的归属节点,将请求发送到目标节点。

(2) 客户端处理重定向

  • MOVED 错误:如果客户端发送请求到错误的节点,目标节点会返回 MOVED <slot> <ip:port> 错误,告知正确的节点地址。客户端更新本地映射表后重试。
  • ASK 错误:在槽迁移过程中,如果键尚未迁移到新节点,源节点会返回 ASK <slot> <ip:port>,客户端临时重定向到新节点(无需更新映射表)。

(3) 示例代码(伪代码)

def get_node(key):
    slot = crc16(key) % 16384
    if slot in local_slot_map:
        return local_slot_map[slot]
    else:
        # 向任意节点发送请求,获取最新槽映射表
        update_local_slot_map()
        return local_slot_map[slot]

4. 关键设计点

(1) 为什么使用 16384 个槽?

  • 平衡性:16384 个槽足够细粒度地分配数据,同时避免槽数量过多导致心跳包过大(Redis 集群节点数通常不超过 1000 个)。
  • 兼容性:CRC16 的哈希值范围是 0~65535,取模 16384 可均匀分布。

(2) 哈希标签(Hash Tags)

  • 场景:某些业务需要多个键存储在同一个节点(如订单 order:1000payment:1000)。
  • 实现:通过 {...} 包裹部分键名,强制使用括号内的子串计算哈希槽:
  {user:1000}.profile  和  {user:1000}.orders  ->  使用 "user:1000" 计算槽

(3) 客户端缓存优化

  • 本地缓存:客户端缓存槽到节点的映射表,减少对集群的查询开销。
  • 自动更新:当遇到 MOVEDASK 错误时,客户端主动更新缓存。

5. 集群节点的通信机制

  • Gossip 协议:节点之间通过 Gossip 协议同步集群状态(如槽分配、节点存活状态),确保所有节点对集群拓扑有一致视图。
  • 心跳包:每个节点周期性发送 PING/PONG 消息,传递自身负责的槽信息和集群元数据。

6. 典型场景分析

(1) 正常读写流程

  1. 客户端计算键 user:123 的槽为 5000
  2. 根据本地映射表,槽 5000 由节点 B 负责。
  3. 客户端直接向节点 B 发送 GET user:123 请求。

(2) 槽迁移中的临时状态

  • 节点 A 正在将槽 5000 迁移到节点 B。
  • 客户端向节点 A 发送请求时,若键 user:123 已迁移,节点 A 返回 ASK 5000 <B的地址>
  • 客户端临时向节点 B 发送请求,无需更新本地映射表。

7. 与传统一致性哈希的对比

特性Redis 哈希槽传统一致性哈希
槽数量固定16384 个槽,便于管理和分配动态哈希环,节点增减需重新计算
数据迁移粒度以槽为单位迁移数据以键为单位迁移数据
客户端缓存显式缓存槽到节点的映射表依赖客户端自行维护哈希环
扩展性槽分配灵活,适合大规模集群节点增减可能导致大量键迁移

总结

Redis 集群通过 哈希槽 + 客户端缓存 + Gossip 协议 实现键的高效定位。其设计核心在于:

  1. 解耦键与节点:通过固定槽数量和动态槽分配,实现数据的灵活分布。
  2. 降低客户端复杂度:客户端只需维护槽映射表,无需感知集群拓扑变化。
  3. 高可用性:槽迁移和故障转移通过 Gossip 协议自动完成,保障服务连续性。
THE END
喜欢就支持一下吧
点赞8 分享