当前位置:首页 > 问答 > 正文

Redis迁移槽突然断了,数据搬运卡住不知道咋整才好

你正在指挥一个大型的仓库搬家,这个仓库里有好几万个带编号的箱子(这些就是Redis里的数据槽),你已经规划好了,把其中一部分箱子,比如从1号到5000号箱子,从旧仓库(源Redis节点)搬到新仓库(目标Redis节点),搬运工(Redis的迁移命令)已经开始干活了,一切看起来挺顺利。

突然,啪嗒一下,连接新旧仓库的传送带(网络)断了,或者新仓库的门口临时被堵住了(目标节点短暂故障),这下糟了,搬家工作卡在了半空中,你可能遇到的情况是:有些箱子已经搬到了新仓库,有些箱子还在传送带上(迁移过程中),而旧仓库这边,因为你已经通知大家“这些箱子要搬走了”,所以对这部分箱子的存取受到了限制,整个系统处于一个非常尴尬和危险的状态:数据可能不一致,客户来存取东西可能会报错,而你站在中间,不知道是该继续搬,还是退回原地,或者干脆重启机器试试(千万别!)。

最重要的一点是:不要慌,更不要轻易去重启Redis节点。 重启很可能让情况变得更复杂,因为节点重启后关于迁移状态的信息可能丢失,导致数据混乱,你需要的是冷静地诊断问题,然后执行清晰的操作。

第一步:立刻检查现状,搞清楚卡在了哪里

你得先看看“搬家现场”到底是个什么状况,这里要用到Redis的两个关键命令:

  1. redis-cli cluster nodes:这个命令能让你看到整个Redis集群的所有节点状态,你需要重点关注那个正在被迁移的槽(比如500号槽),看看它当前被标记为什么状态,在迁移过程中,这个槽的状态应该是migrating(从源节点看)和importing(从目标节点看),如果网络断了很久,可能状态会卡住。
  2. redis-cli cluster info:这个命令给你一个集群健康的整体概览,你要看cluster_state这一行,如果显示是fail,那说明已经有节点被判定为下线了,问题可能比较严重,如果是ok,那还算不幸中的万幸。

通过这两个命令,你能大致判断出是哪个槽的迁移出了问题,以及集群的整体健康度。

第二步:查明中断的原因,解决它

Redis迁移槽突然断了,数据搬运卡住不知道咋整才好

搬家卡住,总有个原因,你得先把根本问题解决掉,才能谈后续的恢复,常见的原因有:

  • 网络问题:这是最常见的原因,检查一下源节点和目标节点之间是否能互相ping通?防火墙规则有没有阻断Redis的集群通信端口(通常是基础端口+10000)?如果是云服务器,安全组设置是否正确?把网络打通是第一步。
  • 目标节点磁盘满了:新仓库没地方放了,搬运工自然就停摆了,用redis-cli info memory连接到目标节点,检查一下used_memory是否接近maxmemory,或者用系统命令df -h看看磁盘空间是否告急,如果是,你需要清理空间或者扩大磁盘。
  • 超时设置:迁移大量数据时,如果某个Key的Value特别大(比如一个几百MB的Hash键),可能会因为迁移时间过长导致超时,你可以适当调整Redis配置文件中的cluster-node-timeout参数(默认15秒),在迁移期间临时调大一点,但迁移完成后要记得改回来。
  • 内存不足:源节点或目标节点在迁移过程中需要额外内存开销,如果系统内存不足,可能导致Redis进程被系统杀死(OOM),检查系统日志(如/var/log/messages)看看有没有OOM的记录。

第三步:根据情况,决定如何恢复迁移

根本问题解决后,你有两个主要的选择:

选择A:继续完成迁移(推荐,如果可能的话)

Redis迁移槽突然断了,数据搬运卡住不知道咋整才好

如果迁移中断的时间不长,集群状态还健康,那么最干净的办法是让迁移流程继续走下去,Redis的迁移命令本身是具备一定容错能力的。

  1. 再次执行迁移命令,你需要重新连接到源节点,使用CLUSTER SETSLOT <slot> MIGRATING <target-node-id>命令,但这次很可能它会提示错误,因为状态已经存在了。
  2. 更直接的方法是,使用Redis内置的修复工具 redis-cli --cluster fix,这个命令会连接到你指定的节点,检查集群中所有槽的分配情况,并尝试修复那些不处于正常服务状态的槽,它会自动尝试重新同步状态,继续未完成的数据搬运,这是比较安全和省心的做法,命令类似:redis-cli --cluster fix 127.0.0.1:6379(填写你集群中任意一个节点的地址)。
  3. 在执行fix之后,再次用cluster nodescluster info检查,确认那个出问题的槽是否已经顺利迁移到了目标节点,并且集群状态恢复为ok

选择B:强制回滚迁移(情况复杂时的备选方案)

如果中断发生了很久,期间已经有客户端在两边读写数据,导致了严重的数据不一致,或者你尝试继续迁移但总是失败,那么可能需要强制回滚,让这个槽回到源节点。

警告:这个操作有风险,可能会导致少量数据丢失,应该是最后的手段。

  1. 在目标节点上:执行CLUSTER SETSLOT <slot> STABLE命令,强制让该槽位稳定下来,停止导入状态。
  2. 在源节点上:同样执行CLUSTER SETSLOT <slot> STABLE命令,停止迁移状态。
  3. 在集群的任意一个主节点上(通常是在源节点),执行CLUSTER SETSLOT <slot> NODE <source-node-id>,明确地将这个槽的所有权重新指派给源节点,这里的<source-node-id>就是源节点的ID,你可以从cluster nodes命令的结果里找到。
  4. 执行这个操作后,集群配置会更新,告诉所有节点“这个槽又归源节点管了”,之后,你可能需要手动检查一下数据的一致性,因为目标节点上可能已经写入了一些新数据,这些数据在回滚后就会丢失。

给你的行动清单:

  1. 别重启:保持节点运行。
  2. 查状态:用cluster nodescluster info看卡在哪个槽,集群是否健康。
  3. 找原因:排查网络、磁盘、内存等基础问题并解决。
  4. 尝试恢复:优先使用redis-cli --cluster fix让系统自动恢复迁移。
  5. 谨慎回滚:如果自动恢复不行,再考虑强制回滚到源节点,并接受可能的数据丢失。
  6. 事后复盘:迁移完成后,一定要复盘为什么中断,优化你的迁移流程(比如在业务低峰期进行、分批迁移、增加监控等),避免下次再掉进同一个坑里。

这种事情确实很让人头疼,但只要你一步步来,先诊断再操作,通常都是可以解决的。