高内存水位下直接reshard会失败,因migrate命令在源节点序列化大数据key易触发oom或阻塞主线程,且目标节点若启用非noeviction策略可能误删迁移中key导致不一致。

高内存水位下扩容,核心是避免迁移过程触发 OOM 或主从同步卡顿导致集群不可用。不能等内存打满再操作,必须在 used_memory_rss 达到物理内存 70% 前启动,且迁移期间要控制单次迁移槽位数、禁用 maxmemory-policy noeviction 以外的驱逐策略。
为什么高内存水位下直接 reshard 会失败
Redis 的 CLUSTER SETSLOT importing/migrating 迁移流程依赖源节点执行 MIGRATE 命令,该命令会临时在源节点构造完整 key-value 序列化数据并发送——若 key 很大(如大 Hash、ZSet)或当前内存已接近上限,极易触发 OOM error 或阻塞主线程;同时目标节点接收后需反序列化写入,若其 used_memory 已超限且配置了 allkeys-lru 类策略,可能误删正在迁移中的 key,造成数据不一致。
-
redis-cli --cluster reshard默认一次性迁移大量槽位(比如 1000+),但高水位下应拆成每次 ≤200 槽 - 迁移期间若源节点触发
eviction,MIGRATE可能返回NOKEY或BUSYKEY,reshard 中断且状态残留 - 目标节点若启用了
maxmemory-policy volatile-ttl,而迁移 key 都没设 TTL,会导致新 key 被优先淘汰
扩容前必须做的三件事
不是先加节点,而是先稳住内存和状态:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 确认所有节点
maxmemory-policy为noeviction(否则迁移中 key 可能被删) - 用
redis-cli -c -h $IP -p $PORT info memory | grep used_memory_rss核实各主节点used_memory_rss,任一节点 ≥ 物理内存 75%,暂停扩容,先做MEMORY PURGE或清理大 key - 检查复制积压缓冲区:若
repl_backlog_size小于 100MB,且从节点延迟 > 100ms,需先调大该值并重启从节点,否则迁移时主从断连概率陡增
安全迁移槽位的关键参数与命令
不用交互式 redis-cli --cluster reshard,改用带约束的非交互方式:
- 指定迁移槽数量:
redis-cli --cluster reshard $EXISTING_NODE --cluster-from $SOURCE_ID --cluster-to $TARGET_ID --cluster-slots 192 --cluster-yes(严格限制 ≤200) - 禁止自动选择源节点:
--cluster-from必须显式传入一个主节点 ID,避免脚本误选高负载节点 - 迁移前手动预热目标节点:对目标节点执行
CONFIG SET activedefrag yes和CONFIG SET lazyfree-lazy-eviction yes,降低接收大数据时的延迟毛刺 - 每轮迁移后等待 60 秒再执行下一轮,用
redis-cli -c -h $TARGET cluster nodes | grep "myself" | awk '{print $3}'确认connected状态未变
容易被忽略的缩容回滚点
如果迁移中途发现目标节点 used_memory_peak_human 上涨过快(如 5 分钟内 +30%),立刻停止并回滚:
- 对目标节点执行
CLUSTER SETSLOT $SLOT NODE $SOURCE_ID(强制把槽还回去) - 对源节点执行
CLUSTER SETSLOT $SLOT STABLE清除 migrating 状态 - 检查
redis-cli -c -h $SOURCE cluster slots输出,确认该槽已不在 importing/migrating 列表中
真正危险的不是迁移慢,而是状态卡在 migrating + importing 之间——此时客户端读写会频繁重定向失败,且 cluster check 无法自动修复。










