一、前言:为什么需要伸缩?
随着业务增长,你的 Redis Cluster 可能面临:
- ❌ 容量不足:内存使用率 > 80%
- ❌ 性能瓶颈:单节点 QPS 超过 8万
- ❌ 资源浪费:低峰期节点闲置
Redis Cluster 支持在线伸缩(无需停机) ,通过 插槽(Slot)迁移 实现数据重平衡。
本文将手把手演示:
✅ 如何安全扩容 (新增主从节点)
✅ 如何优雅缩容 (下线节点并迁移数据)
✅ 全程业务无感知!
二、环境准备
2.1 当前集群状态(3 主 3 从)
| 节点 | 端口 | 角色 | 负责 Slot |
|---|---|---|---|
| node1 | 7001 | master | 0--5460 |
| node2 | 7002 | master | 5461--10922 |
| node3 | 7003 | master | 10923--16383 |
| node4 | 7004 | slave | → node1 |
| node5 | 7005 | slave | → node2 |
| node6 | 7006 | slave | → node3 |
2.2 目标
- 扩容 :新增
node7(7007)主 +node8(7008)从,接管部分 slot - 缩容 :下线
node3(7003),将其 slot 迁移至其他节点
💡 前提:已搭建 Redis Cluster(参考前文《Redis 搭建分片集群》)
三、第一部分:在线扩容(新增主从节点)
3.1 步骤 1:启动新节点
创建配置目录
bash
mkdir -p /opt/redis-cluster/{7007,7008}
配置 redis.conf(以 7007 为例)
port 7007
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes
protected-mode no
bind 0.0.0.0
daemonize yes
dir /opt/redis-cluster/7007
⚠️ 注意:7008 配置类似,仅改端口和 dir
启动节点
bash
redis-server /opt/redis-cluster/7007/redis.conf
redis-server /opt/redis-cluster/7008/redis.conf
此时新节点是孤立节点,未加入集群。
3.2 步骤 2:将新主节点加入集群
bash
# 任选一个现有节点执行
redis-cli --cluster add-node 192.168.1.10:7007 192.168.1.10:7001
192.168.1.10:7007:新主节点192.168.1.10:7001:集群中任意现有节点
✅ 验证:
bash
redis-cli -p 7001 cluster nodes
# 应看到 7007 节点,角色为 master,但 slots 为空
3.3 步骤 3:将新从节点挂到新主
bash
redis-cli --cluster add-node \
--cluster-slave \
--cluster-master-id <7007的node-id> \
192.168.1.10:7008 \
192.168.1.10:7001
🔑 如何获取 node-id?
bashredis-cli -p 7007 cluster myid
✅ 验证:
bash
redis-cli -p 7001 cluster nodes | grep 7008
# 应显示:slave <7007-node-id>
3.4 步骤 4:迁移插槽(重平衡数据)
方法一:自动重平衡(推荐)
bash
redis-cli --cluster rebalance 192.168.1.10:7001 \
--cluster-use-empty-masters \ # 允许空主参与分配
--cluster-threshold 1 # 最小不平衡比例(%)
方法二:手动指定迁移量
bash
# 从每个老主迁移 1000 个 slot 到 7007
redis-cli --cluster reshard 192.168.1.10:7001
交互式输入:
How many slots do you want to move?→3000What is the receiving node ID?→<7007-node-id>Source node IDs→ 输入all(从所有主节点匀出)
⏱️ 迁移过程:
- 客户端可能收到
ASK重定向- 业务无中断(Lettuce/Jedis 自动处理)
✅ 验证迁移结果:
bash
redis-cli -p 7001 cluster slots
# 应看到 7007 负责部分 slot(如 0-1000, 5461-6461, ...)
四、第二部分:在线缩容(安全下线节点)
目标 :下线
node3(7003)及其从节点node6(7006)
4.1 步骤 1:迁移 node3 的所有插槽
bash
# 查看 node3 负责的 slot 范围
redis-cli -p 7003 cluster nodes | grep myself
# 输出示例:... master - 0-0 3 connected 10923-16383
# 将其 slot 全部迁移到 node1(7001)
redis-cli --cluster reshard 192.168.1.10:7001
交互输入:
slots to move:5461(16383 - 10923 + 1 = 5461)receiving node ID:<7001-node-id>source node ID:<7003-node-id>done
✅ 关键:确保迁移完成后再下线!
4.2 步骤 2:下线从节点(7006)
bash
# 在主节点执行 forget
redis-cli -p 7001 cluster forget <7006-node-id>
# 停止 7006 进程
kill $(pgrep -f "7006")
⚠️ 必须先 forget 再 kill,否则集群会尝试重连。
4.3 步骤 3:下线主节点(7003)
确认其 slots 已清空:
bash
redis-cli -p 7003 cluster nodes | grep myself
# 应显示:connected(无 slot 范围)
执行下线:
bash
# 在其他节点 forget
redis-cli -p 7001 cluster forget <7003-node-id>
# 停止进程
kill $(pgrep -f "7003")
✅ 最终验证:
bash
redis-cli -p 7001 cluster nodes
# 应不再显示 7003 和 7006
五、客户端影响与最佳实践
5.1 业务是否中断?
- 扩容/缩容期间 :
- 写操作:可能短暂延迟(slot 迁移中)
- 读操作:自动重定向(
MOVED/ASK)
- 现代客户端(Lettuce/Jedis)自动处理 ,应用层无感知
5.2 生产环境建议
| 场景 | 建议 |
|---|---|
| 扩容时机 | 内存使用率 > 70%,或 CPU 持续 > 80% |
| 迁移速度 | 使用 --cluster-timeout 控制(避免网络打满) |
| 监控指标 | 关注 migrate_cached_sockets, evicted_keys |
| 回滚方案 | 迁移前备份 AOF/RDB |
5.3 避免踩坑
- ❌ 不要直接 kill 节点(先
forget) - ❌ 不要在高峰期执行大规模迁移
- ✅ 迁移后验证数据一致性(抽样比对)
六、自动化脚本示例(扩容)
bash
#!/bin/bash
# auto_expand.sh
NEW_MASTER_PORT=7009
NEW_SLAVE_PORT=7010
EXISTING_NODE="192.168.1.10:7001"
# 1. 启动新节点(略)
# 2. 加入集群
redis-cli --cluster add-node 192.168.1.10:$NEW_MASTER_PORT $EXISTING_NODE
MASTER_ID=$(redis-cli -p $NEW_MASTER_PORT cluster myid)
redis-cli --cluster add-node \
--cluster-slave \
--cluster-master-id $MASTER_ID \
192.168.1.10:$NEW_SLAVE_PORT \
$EXISTING_NODE
# 3. 自动重平衡
redis-cli --cluster rebalance $EXISTING_NODE --cluster-use-empty-masters
echo "扩容完成!"
七、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!