生产环境redis集群扩容最可控路径是用cluster nodes解析拓扑并由shell脚本驱动:精准提取节点信息、按内存水位计算迁移量、监控迁移状态、校验客户端兼容性、最终执行cluster check验证。

直接用 CLUSTER NODES 输出解析拓扑 + Shell 脚本驱动扩容,是生产环境最可控的自动化路径。关键不在于“全自动”,而在于把人工易错、耗时的判断和校验步骤固化进脚本,确保每次操作可重复、可验证、可中断回滚。
从 CLUSTER NODES 提取真实拓扑结构
CLUSTER NODES 的每行包含节点 ID、IP:port、角色(master/slave)、状态(connected/fail)、从属关系、槽位范围等字段。Shell 脚本需精准切分并过滤,不能依赖固定列数(因注释、空格、Gossip 临时状态可能干扰)。
- 用
awk '{print $1,$2,$3,$9}'提取核心四元组:node_id、addr、role、slots(最后一段为槽位区间或空) - 用
grep -v 'fail\|noaddr'排除异常节点,避免误选故障源 - 对 master 节点,用
tr -d '\r\n' | sed 's/ \+/,/g'标准化槽位字符串,再用awk -F',' '{print NF-1}'统计已分配 slot 数量(注意空行和“-”占位) - 新加入但未分配 slot 的节点,
$9字段为空或仅含-,这是识别“待扩容目标”的唯一可靠依据
自动计算迁移量并生成 reshard 命令
扩容不是均分,而是按内存水位驱动:先查各主节点 INFO memory | grep used_memory_human,再换算成相对占比,最后按比例从高水位节点匀出 slot 给新节点。
- 用
redis-cli -h $host -p $port INFO memory 2>/dev/null | awk -F': ' '/used_memory_human/ {print $2}' | sed 's/[KMGB]//'提取无单位数值(如 12500 表示 12.5GB) - 总内存 = 所有主节点 used_memory_human 求和;单个节点权重 = 自身内存 / 总内存
- 目标迁移 slot 数 =
int(16384 × 权重 × 0.9)(留 10% 余量防后续增长);上限设为 1000,超量则分批 - 命令拼接必须显式指定
--from和--to,例如:redis-cli --cluster reshard $existing_node --from $src_node_id --to $dst_node_id --slots $count -y
迁移过程监控与安全退出机制
脚本不能只发命令就结束。必须等待实际数据搬运完成,并捕获失败信号,否则会留下“slot 已分配但 key 未迁移”的危险中间态。
- 执行 reshard 后,用
timeout 600 redis-cli -h $dst_host -p $dst_port CLUSTER NODES 2>/dev/null | grep "$dst_node_id" | awk '{print $9}'每 30 秒轮询一次目标节点槽位字段,直到非空且含数字区间 - 同时检查源节点是否已移出对应 slot:对比迁移前后
CLUSTER NODES | grep $src_node_id | awk '{print $9}',确认原区间消失 - 若 10 分钟内未完成,或出现
LOADING Redis is loading the dataset in memory等错误,立即redis-cli --cluster failover $dst_node_id中止并退出 - 所有 redis-cli 命令统一加
-a $auth和--no-auth-warning,避免交互中断
客户端兼容性检查必须嵌入脚本
扩容成功但客户端报 MOVED/ASK,等于没扩。脚本应在迁移前强制验证 SDK 是否满足条件。
- 调用
redis-cli -h $any_master -p $port CLUSTER SLOTS获取当前拓扑快照,提取所有 slot → node 映射 - 模拟客户端行为:取 100 个高频 key(如
KEYS user:* | head -100),用crc16(key) % 16384计算其所属 slot,再查映射表确认是否落在新节点上 - 若发现 >5% 的 key 被重定向,暂停脚本并提示:“客户端缓存未刷新,请检查 Jedis.setRefreshPeriod(0) 或 redis-py 的 decode_responses=False 设置”
- 迁移完成后,自动触发一次
redis-cli --cluster check $any_node,输出 “OK” 才标记本次扩容完成











