返回首页

Redis 架构篇5.4: 集群扩缩容与故障处理

适用版本:Redis 7.2.x

理解了 Redis Cluster 的哈希槽模型之后,真正进入生产实践时,最常见的问题就变成了下面这些:

  • 集群容量不够了,怎么安全扩容?
  • 某个节点负载太高,怎么迁槽均衡?
  • 想下线一台节点,应该先做什么?
  • 主节点故障后,集群会怎么恢复?
  • 如果迁槽过程中出问题,应该怎样排查?

这些问题的共同关键词,其实就两个:

  1. 槽位迁移
  2. 故障收敛

因为 Redis Cluster 的数据不是抽象地“放在某台机器上”,而是明确地落在 16384 个哈希槽上。只要你理解扩缩容本质上是在重新分配槽位,故障处理本质上是在恢复槽位服务能力,这一章就会顺很多。

这篇文章会把扩容、缩容、重平衡、节点下线、主从切换、常见故障排查串成一个完整的运维视角。


一、先建立一个核心心智模型:操作的对象不是节点,而是槽位

很多初学者做 Cluster 运维时容易掉进一个误区:

以为扩容就是“加台机器”,缩容就是“删台机器”。

其实对 Redis Cluster 来说,更准确的说法是:

  • 扩容:新增节点并让其承接一部分槽位
  • 缩容:把目标节点上的槽位迁走,再移除节点
  • 负载均衡:重新分配槽位,使多个主节点更均衡
  • 故障处理:让失效槽位尽快重新由可用主节点接管

所以后面无论看到 reshardrebalanceadd-nodedel-node,都要记住:

Cluster 运维的本质是槽位与主节点映射关系的调整。


二、一个典型生产集群图景

假设当前集群是 3 主 3 从:

Master1 (0~5460)    -> Replica1
Master2 (5461~10922)-> Replica2
Master3 (10923~16383)-> Replica3

随着业务增长,可能出现几种典型情况:

1. 容量不够

某几个主节点内存接近上限,需要新增主节点承接部分槽位。

2. 负载不均

虽然总容量还够,但某个主节点热点太集中,需要通过迁槽做均衡。

3. 节点要下线

比如机器老化、硬件迁移、云资源调整,需要从集群里删除一个主节点或副本节点。

4. 节点发生故障

主节点宕机、网络隔离、磁盘异常等,会触发自动或人工故障处理。

这四类问题,基本覆盖了 Redis Cluster 最常见的运维场景。


三、扩容:新增节点后为什么还看不到容量变化

1. 扩容的第一步:把新节点加入集群

如果你新增了一台 Redis 节点,先要让它加入现有集群。

例如:

redis-cli --cluster add-node 192.168.10.20:7006 192.168.10.10:7000

含义是:

  • 192.168.10.20:7006 加入集群;
  • 192.168.10.10:7000 是集群中已存在的任一节点,用来作为入口发现拓扑。

2. 为什么加完节点还不能立刻分担流量

因为新主节点刚加入时,通常还是一个空主节点,还没有任何槽位。

也就是说:

  • 它已经是集群成员;
  • 但它还不负责任何 key;
  • 所以业务流量和数据不会自动迁过去。

这也是很多人第一次扩容时最容易困惑的点。

3. 真正让扩容生效:迁槽

要让新节点承接数据,必须把现有节点的一部分槽位迁到新节点上。

这通常通过 reshardrebalance 完成。


四、扩容的两种常见方式:reshard 与 rebalance

1. reshard:明确迁移多少槽、从谁迁到谁

示例:

redis-cli --cluster reshard 192.168.10.10:7000

执行后通常会交互式询问:

  • 迁移多少个槽;
  • 目标节点 ID 是谁;
  • 从哪些源节点迁出;
  • 是否确认执行。

这种方式适合:

  • 你明确知道要迁哪些槽;
  • 想精细控制扩容过程;
  • 只对局部节点做迁移。

2. rebalance:让工具尽量自动做均衡

示例:

redis-cli --cluster rebalance 192.168.10.10:7000 --cluster-use-empty-masters

它更像“自动平衡器”,适合:

  • 新增了空主节点;
  • 希望整体重新均衡槽位分布;
  • 不想手工计算每个节点该迁多少槽。

3. 两者怎么选

可以简单理解为:

  • reshard:偏手工、偏精细;
  • rebalance:偏自动、偏整体均衡。

生产里如果只是一次常规扩容,很多团队会优先用 rebalance;如果要严格控制迁移源和目标,则更常用 reshard


五、一次标准扩容流程应该怎么走

下面给出一个更贴近实践的扩容步骤。

步骤 1:新增主节点

redis-cli --cluster add-node 192.168.10.20:7006 192.168.10.10:7000

步骤 2:给新主增加副本

redis-cli --cluster add-node 192.168.10.21:7007 192.168.10.10:7000 --cluster-slave --cluster-master-id <new-master-id>

这样可以保证新主节点也具备副本高可用能力。

步骤 3:迁槽或重平衡

redis-cli --cluster rebalance 192.168.10.10:7000 --cluster-use-empty-masters

步骤 4:检查槽位是否均衡

redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster info

重点关注:

  • 槽位是否仍然全部覆盖 16384;
  • 新主节点是否已获得槽位;
  • 集群状态是否仍为 ok
  • 迁移后热点是否得到缓解。

步骤 5:观察业务层面指标

扩容成功不只看命令执行成功,还要看:

  • 各主节点 CPU 是否更均衡;
  • 内存占用是否下降;
  • 客户端是否出现异常 MOVED / ASK 重试激增;
  • 业务 RT 是否恢复稳定。

六、缩容:为什么不能直接删主节点

1. 直接删除主节点会出问题

如果某个主节点还持有槽位,你不能直接把它从集群删除。因为这会导致:

  • 一部分槽位无人负责;
  • 对应 key 无法访问;
  • 集群状态可能变成异常。

2. 缩容的正确思路

缩容必须先做两件事:

  1. 把目标主节点的槽位全部迁走;
  2. 确认它变成空主节点后,再删除。

3. 一个典型缩容流程

假设要下线某个主节点 <old-master-id>

第一步:把槽位迁出

redis-cli --cluster reshard 192.168.10.10:7000

交互时把源节点指定为 <old-master-id>,目标可以选择一个或多个接收节点。

第二步:确认该节点已无槽位

redis-cli -p 7000 cluster nodes

确认该主节点后面不再挂任何槽位区间。

第三步:删除该主节点

redis-cli --cluster del-node 192.168.10.10:7000 <old-master-id>

4. 如果还有副本怎么办

如果这个主节点有副本,通常还要根据规划:

  • 一并删除副本;
  • 或先把副本改挂到其他主节点;
  • 或保留作为其他主节点的新副本。

所以缩容不仅是“删主”,也是“重整主从关系”。


七、迁槽过程中到底发生了什么

理解迁槽细节,对于排查扩缩容问题非常有帮助。

1. 槽位迁移不是简单改个配置

真正的迁槽过程涉及:

  • 设置源节点与目标节点的槽位迁移状态;
  • 将该槽位内的 key 逐步迁往目标节点;
  • 在迁移期间通过 ASK 引导客户端请求;
  • 最终把槽位正式归属切到目标节点,并返回 MOVED

2. 为什么迁槽期间会看到 ASK

因为这是一个过渡阶段:

  • 槽位还没完全迁完;
  • 但有些 key 已经在目标节点;
  • 为了不中断服务,客户端会被临时引导到目标节点。

3. 为什么迁槽会带来性能抖动

常见原因有:

  • key 数量多,迁移耗时长;
  • 存在大 key,单次迁移成本高;
  • 业务流量本来就高;
  • 网络带宽有限;
  • 客户端重定向重试增加。

所以生产中不建议在高峰时段做大规模迁槽。


八、故障处理一:主节点宕机时,Cluster 会怎样恢复

1. 故障检测

Cluster 节点之间会持续交换状态信息。当多数主节点认为某个主节点不可达时,该节点会被标记为故障。

2. 副本发起故障转移

如果这个主节点有可用副本,副本会尝试竞选并提升为新主,接管原来的槽位。

3. 槽位归属随新主接管

一旦副本提升成功,这批槽位仍然可用,只是服务节点从旧主换成了新主。

4. 客户端刷新拓扑

客户端会在收到重定向或拓扑更新后,逐步把流量切到新主节点。

5. 一个必须清楚的边界

由于复制仍然是异步的,所以主节点故障瞬间仍可能丢失最近尚未同步到副本的数据。


九、故障处理二:如果主节点没有副本会怎样

这是一个非常危险的场景。

1. 没有副本就没有自动接管者

如果某个主节点挂了,但没有可用副本,那么它负责的槽位就无人接管。

2. 集群可能进入不可服务状态

这会导致:

  • 部分 key 无法访问;
  • 集群健康状态下降;
  • 对应业务分片直接报错。

3. 这也是为什么生产上不建议“裸主节点”

每个主节点最好都有至少一个副本,并且尽量分布在不同故障域中。


十、故障处理三:副本提升后,原主恢复了怎么办

通常原主恢复后不会自动抢回主角色,而是需要重新纳入当前集群拓扑。

常见做法是:

  • 让它以副本身份重新加入;
  • 挂到当前新的主节点下;
  • 等数据追平后再决定是否保留或后续再做角色调整。

这和 Sentinel 模式的思路是类似的:

故障恢复后的旧主,通常先降级成副本,而不是直接恢复旧地位。

这样可以避免反复切换带来的不稳定。


十一、故障处理四:网络分区与误判要怎么看

Redis Cluster 不是魔法系统,网络分区仍然是最复杂的故障之一。

1. 典型风险

  • 某个主节点并没有真正宕机,只是和大多数节点失联;
  • 某个副本与部分节点通信不稳定;
  • 客户端与节点看到的拓扑不一致。

2. 可能表现

  • 请求报超时;
  • MOVED / ASK 重定向异常增多;
  • 集群状态短时间波动;
  • 某些分片可用、某些分片不可用。

3. 排查重点

优先看:

  • cluster info 是否为 ok
  • cluster nodes 中节点状态是否有 failhandshakedisconnected
  • 机器和可用区网络是否抖动;
  • 客户端错误日志是否集中在某几个槽位。

十二、常用运维命令清单

1. 查看集群状态

redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster slots

2. 添加节点

redis-cli --cluster add-node 192.168.10.20:7006 192.168.10.10:7000

3. 添加副本

redis-cli --cluster add-node 192.168.10.21:7007 192.168.10.10:7000 --cluster-slave --cluster-master-id <master-id>

4. 迁槽

redis-cli --cluster reshard 192.168.10.10:7000

5. 自动均衡

redis-cli --cluster rebalance 192.168.10.10:7000 --cluster-use-empty-masters

6. 删除节点

redis-cli --cluster del-node 192.168.10.10:7000 <node-id>

7. 集群检查

redis-cli --cluster check 192.168.10.10:7000

这个命令很适合在扩缩容、迁槽、故障恢复后做健康检查。


十三、常见问题

1. 为什么扩容后新节点仍然几乎没有流量?

因为你只是把节点加进了集群,但还没有给它分配槽位。没有槽位,就没有数据,也接不到业务请求。

2. 为什么缩容时不能直接 del-node 主节点?

因为主节点可能还负责槽位。必须先把槽位迁空,变成空主节点后才能安全删除。

3. 迁槽时业务为什么会抖?

常见原因有:

  • 迁移 key 太多;
  • 存在大 key;
  • 客户端重定向重试增多;
  • 网络带宽不足;
  • 正好碰上业务高峰。

4. rebalancereshard 有什么区别?

  • reshard 更像手工指定迁移计划;
  • rebalance 更像自动全局均衡工具。

5. 主节点挂了但为什么没有自动恢复?

常见排查方向:

  • 它是否有可用副本;
  • 副本是否也不健康;
  • 集群是否失去多数派;
  • 网络分区是否导致故障判断异常。

6. 扩缩容时最怕什么?

通常最怕三件事:

  • 高峰期做大规模迁槽;
  • 没提前发现大 key;
  • 没验证客户端对 MOVED / ASK 的处理能力。

十四、实践建议

1. 扩容前先看是不是“容量问题”还是“热点问题”

有时候看起来某个节点压力大,不一定是内存不够,也可能只是热点 key 或热点槽位集中。盲目扩容不一定治本。

2. 扩容时尽量补齐主从对

不要只加主节点不加副本,否则集群虽然容量变大了,但高可用边界变差了。

3. 迁槽前先排查大 key

大 key 会显著拖慢迁槽,也容易造成请求抖动。生产里最好先做一次大 key 扫描和风险评估。

4. 尽量避开流量高峰做迁移

扩缩容本质是在线数据搬运,越高峰风险越高。最好选低峰窗口,并准备回滚或限流预案。

5. 每次操作后都做健康检查

不要只看某条命令返回成功。至少要检查:

  • 槽位是否完整覆盖;
  • 节点角色是否符合预期;
  • 集群状态是否 ok
  • 业务侧错误率是否正常。

6. 客户端拓扑刷新策略必须成熟

很多集群问题最后不是 Redis 本身没恢复,而是客户端长期缓存旧路由,导致业务仍然请求错误节点。


十五、小结

Redis Cluster 的扩缩容与故障处理,看起来步骤很多,但核心逻辑其实很统一:

  1. 扩容不是单纯加机器,而是新增节点后重新分配槽位;
  2. 缩容不是直接删机器,而是先迁空槽位,再删除节点;
  3. 迁槽期间会出现 ASK,迁移完成后会进入稳定 MOVED 路由;
  4. 主节点故障时,副本会尝试提升为新主接管原有槽位;
  5. 所有操作最终都要回到一个问题:16384 个槽位当前是否被健康、均衡、可恢复地管理。

如果你把 Redis Cluster 运维理解成“槽位生命周期管理”,很多复杂命令就不再是零散技巧,而会变成一套前后连贯的操作体系。掌握这一点,才算真正跨过了 Cluster 从“会搭”到“会管”的门槛。


📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

Redis 架构篇5.3: Cluster 集群基础

下一篇

Redis工程实践6.1: 缓存设计模式详解