文章目录

Redis集群中的Hash Slot分配与数据迁移过程

发布于 2026-05-07 01:27:00 · 浏览 6 次 · 评论 0 条

Redis集群中的Hash Slot分配与数据迁移过程

Redis集群通过将数据拆分并存储在多个节点上,实现了水平扩展。这种数据分片的机制被称为Hash Slot(哈希槽)。掌握槽位的分配逻辑与数据迁移的具体步骤,是维护高可用Redis集群的核心技能。


一、 理解Hash Slot的分配原理

Redis集群预设了 16384 个槽位。集群中的每一个键值对都属于这 16384 个槽位中的某一个。数据并不是直接绑定在节点IP上,而是绑定在槽位上,槽位再分配给具体的节点。

当客户端读写数据时,集群会根据键名计算出一个数值,以决定该数据去往哪个节点。计算公式如下:

$$ \text{Slot ID} = \text{CRC16}(\text{key}) \pmod{16384} $$

这意味着:

  1. 一致性:同一个键名计算出的槽位编号永远相同。
  2. 分散性:足够多的键名会均匀地覆盖所有槽位。

为了实现负载均衡,槽位通常被均匀地分配给集群中的主节点。例如,在一个包含3个主节点的集群中,理想的分配状态如下表所示:

节点标识 负责的槽位范围 槽位数量
Master A 0 - 5460 5461
Master B 5461 - 10922 5462
Master C 10923 - 16383 5461

二、 准备工作:获取节点ID

在进行任何槽位迁移之前,必须获取源节点(迁出方)和目标节点(迁入方)的ID。

连接 到集群中的任意一个节点,执行 命令:

redis-cli -c -p 7000 cluster nodes

查看 输出结果,找到对应IP地址和端口的长字符串ID(类似 3c3a0c74aae0b82b4323c5a2f8a6b7c8),并记录下来。假设源节点ID为 <source_id>,目标节点ID为 <target_id>


三、 数据迁移的核心流程

手动迁移槽位是一个非常精细的过程,主要分为四个阶段:标记、迁移、指派、广播。为了保证数据不丢失且服务不中断,必须严格按照顺序执行。

以下是迁移逻辑的流程图,展示了节点间如何协作完成槽位交接:

graph LR A[客户端] -->|1. 访问数据| B[源节点] B -->|2. 返回数据| A A -->|3. 发起迁移请求| C[管理员/工具] C -->|4. 设置 IMPORTING 状态| D[目标节点] C -->|5. 设置 MIGRATING 状态| B B -->|6. 获取槽内Key列表| B B -->|7. 逐个迁移Key数据| D B -->|8. 持有Key但返回 ASK| A A -->|9. 重试访问 ASKING| D C -->|10. 确认槽位归属| D D -->|11. 广播新配置| E[集群所有节点]

四、 实操步骤:手动迁移单个槽位

假设我们要将槽位 1000 从源节点迁移到目标节点。

1. 标记目标节点(准备导入)

连接 到目标节点,执行 IMPORTING 命令。这告诉目标节点:“我准备接收槽位 1000 的数据了,如果源节点发来数据,请收下”。

redis-cli -c -p 7001 CLUSTER SETSLOT 1000 IMPORTING <source_id>

2. 标记源节点(准备导出)

连接 到源节点,执行 MIGRATING 命令。这告诉源节点:“我准备把槽位 1000 移交出去,如果客户端访问该槽位且Key不存在,告诉它去目标节点找”。

redis-cli -c -p 7000 CLUSTER SETSLOT 1000 MIGRATING <target_id>

3. 获取槽位内的Key列表

连接 到源节点,查询 槽位 1000 中目前有多少个键。COUNT 参数指定一次返回的键数量(此处设为10)。

redis-cli -c -p 7000 CLUSTER GETKEYSINSLOT 1000 10

该命令会返回该槽位下的键名列表,例如 key1, user:1001 等。

4. 迁移键数据

对上一步获取到的每一个键,执行 MIGRATE 命令。这个命令会将键从源节点原子性地移动到目标节点。

redis-cli -c -p 7000 MIGRATE <target_ip> 6379 <key_name> 0 5000
  • <target_ip>:目标节点的IP地址。
  • 6379:目标节点端口。
  • <key_name>:具体的键名。
  • 0:表示不超时(或指定超时时间)。
  • 5000:表示如果有多个相关键(如哈希结构的字段),也一并复制。

重复 步骤3和步骤4,直到 CLUSTER GETKEYSINSLOT 返回空列表,表示该槽位下的所有数据已搬空。

5. 确认槽位归属

当源节点槽位为空后,需要在集群任意节点上执行 SETSLOT 命令的 NODE 子命令。这步操作会将槽位 1000 的所有权正式指派给目标节点,并向集群广播这一变更。

redis-cli -c -p 7000 CLUSTER SETSLOT 1000 NODE <target_id>

五、 批量迁移的高效方法

手动逐个迁移槽位效率极低且容易出错。Redis官方提供了内置工具 redis-cli--cluster reshard 功能,可以自动化完成上述所有步骤。

打开 终端,运行 下面的命令:

redis-cli --cluster reshard <your_cluster_ip>:7000

工具会进入交互模式,按照 提示操作:

  1. 输入 要移动的槽位总数(例如 1000)。
  2. 输入 接收这些槽位的目标节点ID。
  3. 输入 源节点ID。如果想从所有其他节点各抽取一部分,输入 all
  4. 输入 yes 确认 执行计划。

工具会自动:

  • 计算每个源节点需要迁出的槽位。
  • 在后台执行 IMPORTING / MIGRATING 标记。
  • 批量移动键数据。
  • 更新集群配置并广播。

六、 迁移过程中的客户端行为

在槽位迁移期间,客户端可能会遇到两类重定向指令,理解它们的区别有助于排查问题:

  • MOVED 重定向:表示槽位已经明确不属于当前节点,且已经完成了归属权变更。客户端必须更新本地缓存,后续请求直接发送给新节点。
  • ASK 重定向:仅在迁移期间出现。表示“槽位还在我这里,但你要找的那个Key刚搬到隔壁了”。客户端需要在下一次请求前发送 ASKING 命令,然后尝试去目标节点读取。客户端不应更新本地槽位缓存,因为下一次请求可能还要找源节点。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文