高级篇 15. 分布式缓存 - 集群伸缩 (扩容与缩容)

3 阅读5分钟

想象一下这样一个场景:你参与研发的核心系统(比如大型政企、国家电网的集中缴费系统)在业务高峰期突遇极高的海量并发,原有的 3 台 Master 内存和 CPU 双双告急。你绝对不可能去“停机升级”,必须要在系统不停运转、用户无感知的情况下,平滑地给集群增加新的服务器来分摊压力。


📚 高级篇 15. 分布式缓存 - 集群伸缩 (扩容与缩容)

一、 核心认知:集群伸缩的本质是什么?

在单机或主从架构中,加机器只能加 Slave(提升读并发),无法提升存储上限。

而在分片集群中,集群伸缩的本质,就是“哈希槽 (Hash Slot)”的重新分配(Resharding)。

  • 扩容(加机器): 启动一台全新的 Master 加入集群。然后从现有的老 Master 手里,匀出一部分哈希槽(连同里面的数据),搬家到新 Master 上。
  • 缩容(减机器): 把准备下线的 Master 手里的哈希槽,全部清空并转移给其他存活的 Master,然后安全地将该节点踢出集群。

二、 实战演练:平滑扩容 (增加节点)

假设我们现有一个 3 台 Master 的集群(端口 8001、8002、8003),现在业务猛增,我们需要加入一台新的节点 8007 帮它们分担压力。

第 1 步:启动新节点并加入集群

首先,用 Docker 或直接运行启动 8007 的 Redis 进程。然后,我们要把它“拉入”现有的群聊:

Bash

# 语法:redis-cli --cluster add-node <新节点的IP和端口> <集群中任意一个老节点的IP和端口>
redis-cli --cluster add-node 192.168.1.101:8007 192.168.1.101:8001

执行成功后,8007 就正式成为了集群的一名 Master。但是,此时它手里有 0 个哈希槽,是个纯粹的“光杆司令”,没有任何数据会路由给它。

第 2 步:重新分配哈希槽 (Reshard) ⚡核心

我们需要给 8007 分配“地盘”了。执行重新分片命令:

Bash

redis-cli --cluster reshard 192.168.1.101:8001

执行后,系统会进入交互模式,问你几个极其关键的问题:

  1. How many slots do you want to move (from 1 to 16384)?

    (你要移动多少个槽?)

    答:原来 16384 个槽 3 个人分,现在 4 个人分。16384 ÷ 4 = 4096。输入 4096。

  2. What is the receiving node ID?

    (谁来接收这些槽?)

    答:输入 8007 节点的全局唯一 ID(通过 cluster nodes 命令可以查到)。

  3. Source node #1:

    (从哪些节点手里抠出这 4096 个槽?)

    答:输入 all。意思是让剩下的 3 个老 Master,每个人平摊捐出三分之一的槽位给 8007。

按下回车,Redis 就会在后台自动把相关的哈希槽以及槽里的海量数据,平滑地迁移到 8007 上。扩容大功告成!


三、 实战演练:安全缩容 (移除节点)

如果业务淡季到来,为了节省服务器成本,我们要把 8007 节点下线。

💥 绝对禁忌: 千万不能直接 kill -9 杀掉 8007 的进程!因为它手里还捏着 4096 个哈希槽,直接杀掉会导致这部分数据彻底丢失,集群状态瞬间变为 FAIL

第 1 步:归还哈希槽 (Reshard)

必须先让 8007 净身出户。再次执行分片重组命令:

Bash

redis-cli --cluster reshard 192.168.1.101:8001
  • 移动多少槽? 输入 4096(它手里所有的槽)。
  • 谁来接收? 输入 8001(或者其他老节点)的 ID。
  • 从谁那里拿? 明确输入 8007 节点的 ID,然后输入 done

等数据迁移完毕后,8007 再次变成了拥有 0 个槽的“光杆司令”。

第 2 步:将节点踢出集群

现在可以安全地将它除名了:

Bash

# 语法:redis-cli --cluster del-node <节点IP和端口> <要删除的节点ID>
redis-cli --cluster del-node 192.168.1.101:8007 <8007的节点ID>

完美谢幕,缩容成功!


四、 大厂核心面试题:迁移过程中的请求路由 (ASK vs MOVED)

这是分布式缓存面试中,区分“背题选手”和“真正懂底层的高手”的试金石。

🗣️ 面试官发难: “在哈希槽从节点 A 迁移到节点 B 的过程中,这个动作可能需要好几分钟。如果在这个节骨眼上,客户端刚好发来一个请求,要读写正在迁移中的那个槽里的数据,Redis 会怎么处理?会报错吗?”

💡 你的破局解析:

“不会报错,Redis 通过 ASK 重定向机制优雅地解决了这个问题。

之前我们学过 MOVED,那是槽位已经彻底确定归属时的永久重定向。

但是在迁移进行中,一个哈希槽的数据有一部分在源节点 A,另一部分已经到了目标节点 B。

  1. 客户端首先还是会去找 源节点 A
  2. 节点 A 会先在自己这里找,如果数据还没搬走,就直接处理并返回。
  3. 如果节点 A 发现数据已经搬走了,它就会给客户端返回一个 ASK 错误(例如 ASK 1234 192.168.1.102:8002)。
  4. ASK 的意思是:‘这个数据正在搬家,仅限这一次,你去节点 B 那里问问看(Ask)。’
  5. 客户端收到 ASK 后,会先向节点 B 发送一个 ASKING 命令打招呼,然后再发送真正的读写请求。

这种设计保证了数据在动态迁移时,业务依然是处于高可用、零中断的状态!”


学习总结

通过这节课,你不仅掌握了通过 add-noderesharddel-node 进行线上系统动态扩缩容的运维实操,还深度剖析了保障迁移期间业务不中断的底层 ASK 机制。

这套机制完美体现了大型系统架构在面对流量洪峰时的极致弹性。