slot迁移卡在migrating状态本质是redis单线程被大key或慢操作阻塞,导致migrate同步执行时无法响应其他请求;需先用scan分批迁移小key、单独处理大key,必要时用cluster setslot slot stable强制恢复。

Slot迁移卡在 MIGRATING 状态,本质是 Redis 主线程被大 Key 或慢操作阻塞,无法推进状态切换 —— 不是网络或配置问题,而是单线程模型下的同步阻塞行为。
为什么 CLUSTER SETSLOT ... MIGRATING 后就卡住不动
执行该命令只是给 slot 打上标记,并不触发实际迁移;真正迁移靠客户端访问触发(ASK 重定向 + MIGRATE 命令)或人工调用 MIGRATE。但只要 slot 下存在一个超大 Hash/List/Set(比如百万级成员),MIGRATE 就会一次性序列化整个结构,阻塞主线程数秒甚至分钟。
- Redis 是单线程处理命令,
MIGRATE是原子同步操作,期间无法响应其他请求 -
redis-cli --cluster migrate工具底层也是反复调用MIGRATE,遇到大 Key 同样卡死 - 日志里持续出现
Node X has slots in migrating state Y,说明该 slot 的迁移逻辑没走完,状态无法提交 - 用
CLUSTER COUNTKEYSINSLOT <slot_id></slot_id>查到 key 数不为 0,但SCAN又扫不出新 key —— 很可能就是那个大 Key 占着 slot 没被移走
绕过自动迁移:用 SCAN + MIGRATE 分批推小 Key
不要依赖集群自动发现和重定向,改为主动、可控的分批迁移。核心是避开大 Key,先搬干净的小 Key,最后单独处理大 Key。
- 先用
redis-cli -c -p 7001 cluster countkeysinslot <slot_id></slot_id>确认 slot 总 key 数 - 用
SCAN 0 MATCH "*{key_pattern}" COUNT 100配合MIGRATE搬普通 key:redis-cli -p 7001 migrate 192.168.1.101 7004 "" 0 5000 replace(注意加TIMEOUT 5000,防无限 hang) - 对疑似大 Key,先用
MEMORY USAGE <key></key>测内存占用,再决定是否跳过或拆分 - 跳过大 Key 的 SCAN:用
SCAN的MATCH排除已知前缀,或用KEYS的替代方案(如业务层记录 key 清单)
强制退出迁移卡死:用 CLUSTER SETSLOT <slot_id> STABLE</slot_id>
当迁移彻底中断、目标节点不可达或大 Key 无法处理时,不能硬等。必须手动清理迁移中间态,否则集群元数据一直不一致。
- 从错误日志里提取卡住的 slot ID,例如
Node 192.168.206.129:7004 has slots in migrating state 15495→ slot ID 是15495 - 登录对应源节点(不是目标节点):
redis-cli -c -p 7004 - 执行:
CLUSTER SETSLOT 15495 STABLE,这会清除MIGRATING标记,让 slot 回归正常服务状态 - 注意:该操作不删除数据,也不回滚已迁移的 key,只重置状态;后续需人工补漏或重新规划迁移
- 切勿在未确认节点角色时乱用
CLUSTER SETSLOT <slot_id> NODE <node_id></node_id></slot_id>—— 这极易引发 slot 不一致
大 Key 拆分必须在迁移前完成
迁移过程本身不支持“流式”或“分片式”传输大结构,所以拆分动作必须前置。线上直接 HSCAN/SSCAN 拆是可行的,但要注意避免拆到一半被迁移中断。
- Hash 拆分示例:把
user:1001:profile拆成user:1001:profile:base、user:1001:profile:setting等,按业务维度切 - 拆分期间禁止写入原 key,可用配置中心临时关闭相关功能模块
- 拆完后用
CLUSTER KEYSLOT确认新 key 落在不同 slot,分散迁移压力 - 如果业务无法停写,只能选低峰期 +
CLIENT PAUSE冻结客户端连接几秒,完成关键拆分
真正难的不是命令怎么敲,而是判断哪个 key 在拖慢整个 slot —— MEMORY USAGE 要逐个试,--bigkeys 只能给方向,最终得靠 SCAN + TYPE + STRLEN/LLEN/HLEN 组合排查。别省这一步。











