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 INFO中cluster_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
该命令会自动完成标记状态、迁移键、更新归属的全过程。
四、重新分片的关键注意事项
- 迁移是逐个键进行的:如果槽位中键很多,迁移可能耗时较长,建议在业务低峰期操作。
- 大键(Big Key)问题:迁移大键会阻塞源节点和目标节点,可能导致超时。应提前发现并拆分大键。
- 网络抖动:
MIGRATE过程中如果网络中断,可能出现键同时存在于两个节点或丢失的情况。Redis 通过MIGRATE的COPY、REPLACE选项和重试机制来降低风险。 - 客户端兼容性:客户端必须支持
MOVED和ASK重定向,否则在重新分片期间会出现访问错误。 - 集群状态监控:迁移期间应通过
CLUSTER INFO、CLUSTER NODES持续观察集群状态,确保cluster_state:ok。
五、总结
Redis Cluster 通过 16384 个槽位实现数据分片,槽位与节点的映射关系决定了键的存储位置。重新分片是在线迁移槽位的过程,涉及 MIGRATING/IMPORTING 状态标记、MIGRATE 键迁移、ASK/MOVED 重定向处理以及最终的槽位归属更新。掌握这些机制,不仅能从容应对面试中关于“Redis Cluster 如何扩容”“ASK 和 MOVED 的区别”“为什么是 16384 个槽位”等问题,更能在实际运维中安全、高效地管理 Redis 集群。
未经允许不得转载:任鹏个人博客 » Redis Cluster 集群的槽位分配和重新分片机制

