Redis Cluster 集群的槽位分配和重新分片机制

Redis Cluster 是 Redis 官方提供的分布式解决方案,它通过数据分片(Sharding)将数据分散到多个节点上,从而实现水平扩展。在 Redis Cluster 中,槽位(Slot) 是数据分片的核心概念,而重新分片(Resharding) 则是集群扩容、缩容以及负载均衡的关键机制。理解槽位分配和重新分片,不仅是面试中的高频考点,也是生产环境运维的必备知识。

一、槽位(Slot)的基本概念

Redis Cluster 将整个键空间划分为 16384 个槽位(0 ~ 16383)。每一个键通过以下公式映射到一个具体的槽位:

slot = CRC16(key) mod 16384

其中,CRC16 是 Redis 自定义的 16 位循环冗余校验算法。集群中的每个主节点负责一部分槽位,槽位与节点之间的对应关系决定了某个键最终存储在哪个节点上。

为什么是 16384 个槽位?

这是一个经典的面试追问。主要原因包括:

  • 心跳包大小:集群节点之间通过 Gossip 协议交换信息,心跳包中会携带自己负责的槽位位图(bitmap)。16384 个槽位对应 16384 个 bit,即 2KB;如果使用 65536 个槽位,则需要 8KB,心跳包会显著增大,浪费带宽。
  • 集群规模限制:Redis Cluster 官方建议的最大节点数为 1000 个。16384 个槽位在 1000 个节点下平均每个节点约 16 个槽位,已经足够均匀;再多的槽位对分片精度的提升有限。
  • 位图压缩效率:16384 个 bit 在节点数量较少时,位图压缩率较高,传输效率更好。

二、槽位的分配方式

1. 自动分配(集群创建时)

使用 redis-cli --cluster create 命令创建集群时,可以通过 --cluster-replicas 指定副本数,Redis 会自动将 16384 个槽位尽量均匀地分配给所有主节点。例如 3 主 3 从的集群,每个主节点大约分到 5461 个槽位。

2. 手动分配

管理员也可以手动指定槽位归属,常用命令包括:

  • CLUSTER ADDSLOTS <slot> [slot ...]:将指定槽位分配给当前节点。
  • CLUSTER DELSLOTS <slot> [slot ...]:从当前节点移除指定槽位。
  • CLUSTER SETSLOT <slot> NODE <node-id>:将槽位指派给指定节点。
  • CLUSTER ADDSLOTSRANGE / CLUSTER DELSLOTSRANGE:按范围批量操作(Redis 7.0+)。

3. 槽位分配的约束

  • 每个槽位在同一时刻只能属于一个主节点。
  • 所有 16384 个槽位必须全部分配完毕,集群才进入 ok 状态(CLUSTER INFOcluster_state:ok)。
  • 如果存在未分配的槽位,集群处于 fail 状态,无法正常提供服务。

三、重新分片(Resharding)机制

重新分片是指将一部分槽位从一个节点迁移到另一个节点的过程。它通常发生在以下场景:

  • 集群扩容:新增主节点后,需要从原有节点迁移部分槽位过去。
  • 集群缩容:下线节点前,需要将其槽位迁移到其他节点。
  • 负载均衡:某些节点槽位过多或数据量过大时,手动调整槽位分布。

重新分片的流程

Redis Cluster 的重新分片是在线进行的,迁移过程中集群仍可对外提供服务。其核心流程如下:

1. 标记迁移状态

假设要将节点 A 的槽位 slot 迁移到节点 B:

  • 在节点 A 上执行 CLUSTER SETSLOT <slot> MIGRATING <B的node-id>,表示该槽位正在迁出。
  • 在节点 B 上执行 CLUSTER SETSLOT <slot> IMPORTING <A的node-id>,表示该槽位正在迁入。

2. 迁移键数据

使用 CLUSTER GETKEYSINSLOT <slot> <count> 获取该槽位下的键列表,然后对每个键执行 MIGRATE 命令,将键值数据从 A 传输到 B。MIGRATE 是原子操作,会同时删除源节点上的键并在目标节点上创建。

3. 处理迁移期间的请求

在迁移过程中,客户端对槽位 slot 中键的访问遵循以下规则:

  • 访问已迁移的键:节点 A 发现键不存在,会返回 ASK 重定向,指引客户端去节点 B 查询。
  • 访问未迁移的键:节点 A 正常处理。
  • 访问不存在的键:如果键在 A 上不存在且未迁移,A 会正常返回空结果(因为可能本来就不存在)。

注意 ASK 重定向与 MOVED 重定向的区别:

  • MOVED:表示槽位已经永久归属于另一个节点,客户端应更新本地槽位映射缓存。
  • ASK:表示槽位仍在迁移中,仅本次请求需要临时重定向到目标节点,客户端不应更新缓存。

4. 完成迁移

所有键迁移完成后,在节点 A 和 B 上分别执行:

CLUSTER SETSLOT <slot> NODE <B的node-id>

该命令会清除迁移/导入状态,并将槽位归属正式更新为节点 B。此后,客户端对该槽位的请求会被 MOVED 重定向到 B。

使用 redis-cli 进行重新分片

实际运维中,通常使用 redis-cli --cluster reshard 命令交互式完成上述流程:

redis-cli --cluster reshard 127.0.0.1:7000 \
  --cluster-from <源节点ID> \
  --cluster-to <目标节点ID> \
  --cluster-slots <迁移槽位数量> \
  --cluster-yes

该命令会自动完成标记状态、迁移键、更新归属的全过程。

四、重新分片的关键注意事项

  1. 迁移是逐个键进行的:如果槽位中键很多,迁移可能耗时较长,建议在业务低峰期操作。
  2. 大键(Big Key)问题:迁移大键会阻塞源节点和目标节点,可能导致超时。应提前发现并拆分大键。
  3. 网络抖动MIGRATE 过程中如果网络中断,可能出现键同时存在于两个节点或丢失的情况。Redis 通过 MIGRATECOPYREPLACE 选项和重试机制来降低风险。
  4. 客户端兼容性:客户端必须支持 MOVEDASK 重定向,否则在重新分片期间会出现访问错误。
  5. 集群状态监控:迁移期间应通过 CLUSTER INFOCLUSTER NODES 持续观察集群状态,确保 cluster_state:ok

五、总结

Redis Cluster 通过 16384 个槽位实现数据分片,槽位与节点的映射关系决定了键的存储位置。重新分片是在线迁移槽位的过程,涉及 MIGRATING/IMPORTING 状态标记、MIGRATE 键迁移、ASK/MOVED 重定向处理以及最终的槽位归属更新。掌握这些机制,不仅能从容应对面试中关于“Redis Cluster 如何扩容”“ASK 和 MOVED 的区别”“为什么是 16384 个槽位”等问题,更能在实际运维中安全、高效地管理 Redis 集群。

未经允许不得转载:任鹏个人博客 » Redis Cluster 集群的槽位分配和重新分片机制

赞 (0) 打赏

评论 0

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

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏