Redis Cluster reshard 迁槽实战与卡顿治理

举报
yd_94907100 发表于 2026/11/12 00:11:23 2026/11/12
【摘要】 从命令到协议讲清 reshard 全流程,定位并治理迁移期卡顿

reshard(迁槽)是 Cluster 扩缩容的核心动作,也是最容易把线上打抖的操作:迁移期间业务请求要走 ASK 重定向,迁移大 key 时主线程会被阻塞,客户端实现不佳还会直接报错。本文基于 Redis 7,先讲命令用法,再下探到协议层的迁槽原语,最后给出卡顿的定位与治理手段。

一、redis-cli 的两种 reshard 用法

交互式适合人工操作,命令会依次询问迁移槽数、目标节点、源节点:

$ redis-cli --cluster reshard 127.0.0.1:6379
>>> How many slots do you want to move (from 1 to 16384)? 1000
>>> What is the receiving node ID? <目标节点 id>
>>> Source node #1: all
>>> Do you want to proceed with the proposed reshard plan (yes/no)? yes

自动化脚本里推荐非交互式参数,一次指定全部要素:

redis-cli --cluster reshard 127.0.0.1:6379 \
  --cluster-from <源节点 id> \
  --cluster-to <目标节点 id> \
  --cluster-slots 1000 \
  --cluster-pipeline 100 \
  --cluster-timeout 60000 \
  --cluster-yes

两个参数直接影响迁移速度与卡顿:--cluster-pipeline 是每次 MIGRATE 命令批量携带的 key 数(默认 10),调大可以减少网络往返;--cluster-timeout 是单次 MIGRATE 的超时,默认 60000 毫秒。执行过程中 redis-cli 每迁移一批 key 就打印一个进度点,配合终端输出可以大致观察迁移速率。

迁移进度还有个量化办法:把每个节点的 offset 与 key 数在迁移前后各采一次,差值就是实际搬走的量。执行期间也可以直接查槽的归属状态:

redis-cli -c -h 10.0.0.11 -p 6379 cluster nodes
# 10.0.0.11:6379@16379 myself,master - 0 1761350402000 1 connected 0-5460
# 10.0.0.12:6379@16379 master - 0 1761350401000 2 connected 5461-10922 [1234->-<目标 id>]
# 10.0.0.13:6379@16379 master - 0 1761350403000 3 connected 10923-16383 [1234-<-<源 id>]

方括号里的 [1234->-<id>] 是 migrating 标记,[1234-<-<id>] 是 importing 标记。这一行输出是判断迁移是否卡住最直接的证据:如果某个槽的标记持续数分钟不变,说明这个槽里的 key 搬不动,通常是有大 key 或者 MIGRATE 超时后反复重试。

二、迁槽在协议层面做了什么

redis-cli 只是编排者,真正的迁槽由一组集群命令完成。以把槽 1234 从节点 A 迁到节点 B 为例:

# 1. 目标节点标记导入状态(必须先做,保证能接收 ASK)
redis-cli -h <B> cluster setslot 1234 importing <A 的 id>
# 2. 源节点标记迁出状态
redis-cli -h <A> cluster setslot 1234 migrating <B 的 id>
# 3. 从源节点分批取 key
redis-cli -h <A> cluster getkeysinslot 1234 100
# 4. 批量迁移(空 key 占位 + KEYS 列表)
redis-cli -h <A> migrate <B 的 IP> 6379 "" 0 60000 KEYS key1 key2
# 5. 迁完后在目标、源节点上确认归属,顺序不能反
redis-cli -h <B> cluster setslot 1234 node <B 的 id>
redis-cli -h <A> cluster setslot 1234 node <B 的 id>

理解这段流程就理解了迁移期的业务表现:槽处于 migrating 状态时,源节点对已存在的 key 正常处理,对不存在的 key 返回 ASK 重定向;客户端向 B 发送 ASKING 后重试该条命令。多 key 命令如果部分 key 已迁走、部分还在源节点,源节点会返回 TRYAGAIN,客户端需要稍后重试。

注意:第 5 步必须先通知目标节点再通知源节点。反过来时若目标节点中途宕机,槽会处于无主状态,即使触发故障转移也无法自动恢复归属。

三、迁移期卡顿的四个来源

第一,MIGRATE 本身是阻塞命令。源节点要序列化 key、走网络传输、等目标节点反序列化并恢复到内存,整个期间源节点主线程不处理其他命令,目标节点同样被占用。单次 MIGRATE 的耗时约等于一个 key 的序列化与传输时间,key 越大阻塞越久。

第二,大 key 是元凶。一个几百 MB 的 hash 经 MIGRATE 迁移时,源节点会秒级无响应,这通常就是「迁移动画走着走着业务就卡了」的直接原因。

第三,ASK 重定向放大延迟。迁移中的槽,不在本节点的 key 都要多一次往返;客户端若不支持 ASK(自研或较老的 SDK),表现为直接抛错。

第四,批量太小导致 RTT 累积。--cluster-pipeline 默认 10,跨机房或网络抖动环境下,迁 10 万个 key 就是上万次往返,迁移窗口被拉长,业务暴露在 ASK 状态下的时间随之变长。

四个来源里,MIGRATE 的阻塞机制最值得下探一层,因为它决定了所有治理手段的上限。MIGRATE 命令在源节点上的执行路径是:查 key 是否存在、调用 dumpCommand 把值序列化成 DUMP 格式、在同一个命令上下文里建立到目标节点的同步连接、发送 RESTORE-ASKING 与负载、等待目标返回、删除本地 key。整条链都在主线程里同步完成,中间没有让出执行权的机会。所以单次 MIGRATE 的耗时等于"序列化 + 一次完整 RTT + 目标节点反序列化",三者相加全部计入源节点的阻塞时间。

这也解释了为什么 --cluster-pipeline 的收益有天花板。它把 N 个 key 合并进一次 MIGRATE,RTT 部分从 N 次降为 1 次,但序列化与反序列化的总工作量不变,而且单个大 key 造成的阻塞时间也不会因为批量而缩短。同机房 RTT 约 0.2 ms 时,把批量从 10 调到 100 能让 RTT 开销下降九成;跨机房 RTT 达到 5 ms 时,同样的调整收益更显著,但是一旦某个 key 有 50 MB,序列化耗时就远超 RTT,调参的作用被彻底掩盖。这就是"先拆大 key,再调参数"的顺序依据。

四、卡顿治理清单

治理的总体思路是:把单次阻塞压短,把迁移窗口收窄。生产上建议按顺序执行:先扫描并拆解迁移范围内的大 key(bigkeys 或 cluster getkeysinslot 逐槽检查);把 reshard 安排在业务低峰,并一次性迁几百个槽就停下来观察 slowlog 与客户端错误,而不是一口气迁完;网络往返多时调大 --cluster-pipeline;迁移期间暂停全库扫描类的运维任务。若迁移中途中断,槽可能残留 importing/migrating 状态,用 redis-cli --cluster fix 127.0.0.1:6379 修复后再继续。

常见坑 / 最佳实践

  1. 先拆大 key 再迁槽。 MIGRATE 对单个 key 是原子阻塞的,几百 MB 的 key 会造成秒级无响应。先治理大 key,或者把含大 key 的槽单独安排在最低峰迁移。
  2. 分批迁移,边迁边看。 一次 reshard 上千个槽的窗口太长。按几百个槽一批,每批结束后检查 SLOWLOG GET、LATENCY 事件与业务 P99,确认无异常再继续。
  3. 确认客户端支持 ASK 重定向。 迁移上线前在测试环境跑一轮小规模 reshard,验证所用 SDK(版本)在 ASK 场景下不报错、不丢请求。
  4. --cluster-pipeline 按网络质量调。 同机房可调到 100 以上;跨机房迁槽数据量又大时,先评估带宽,避免 RDB 流量与迁移流量互相挤压。
  5. 中断的迁移必须收尾。 残留的 importing/migrating 状态会让该槽持续返回 TRYAGAIN 与 ASK,用 --cluster fix 或手工 SETSLOT STABLE 清理。

小结

  • reshard 的本质是 IMPORTING/MIGRATING 标记、GETKEYSINSLOT 取 key、MIGRATE 批量搬运、SETSLOT 确认归属这四步原语的循环。
  • 迁移期源节点对不存在的 key 返回 ASK,多 key 命令出现部分迁移时返回 TRYAGAIN,客户端要能处理这两种错误。
  • 卡顿的四个来源是 MIGRATE 阻塞、大 key、ASK 往返与批量过小,对应解法分别是低峰、拆 key、验证客户端、调 pipeline。
  • 迁槽顺序有讲究:目标节点先 IMPORTING,归属确认时目标节点先于源节点 SETSLOT。
  • 分批、观察、再继续是生产迁槽的节奏,中断残留状态要用 fix 收尾。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。