Redis Cluster扩缩容的触发时机
Redis Cluster在生产环境中最常见的运维操作就是扩容和缩容。扩容的信号:内存使用率持续超过80%、命令延迟P99超过阈值、客户端报MOVED重定向频繁。缩容的信号:业务迁移后大量Slot空转、夜间低峰内存使用率低于30%、节点故障后需要移除。
Redis Cluster的数据分布以16384个Slot为基本单位,每个Master节点负责一部分Slot。扩容就是加入新节点并将部分Slot迁移过去;缩容是先将目标节点的Slot迁走,再移除空节点。迁移过程中集群正常服务,请求路由到正在迁移的Slot时,源节点会返回ASK重定向指向目标节点,客户端透明处理。
Redis Cluster扩容操作详解
场景:3主3从集群扩容为4主4从
第一步:启动新节点并加入集群:
# 启动新Master节点(端口7006)
redis-server redis-7006.conf
# 启动新Slave节点(端口7007,作为7006的从节点)
redis-server redis-7007.conf
# 将新Master加入集群
redis-cli --cluster add-node 10.0.1.16:7006 10.0.1.1:7001
# 将新Slave加入集群并指定Master
redis-cli --cluster add-node 10.0.1.16:7007 10.0.1.1:7001 \
--cluster-slave --cluster-master-id <新Master的Node ID>
加入集群后新节点不负责任何Slot,所有请求不会路由到新节点。
第二步:迁移Slot到新节点:
# 交互式迁移(适合少量Slot测试)
redis-cli --cluster reshard 10.0.1.1:7001
# 系统会依次询问:
# 1. 迁移多少个Slot? 输入4096(16384/4=4096,均衡分配)
# 2. 目标节点ID? 输入新Master的Node ID
# 3. 源节点? 输入all(从所有现有Master均匀迁出)
# 非交互式迁移(适合脚本化)
redis-cli --cluster reshard 10.0.1.1:7001 \
--cluster-slots 4096 \
--cluster-target <新Master-Node-ID> \
--cluster-from all \
--cluster-yes
迁移过程中每个Key的迁移步骤是:源节点执行MIGRATE命令将Key的TTL和数据原子的转移到目标节点,然后标记该Slot为迁移中状态。整个Slot迁移完成后,源节点更新Slot映射表。迁移期间对该Slot的请求:如果在源节点找到Key则正常处理;如果Key已被迁移,源节点返回ASK重定向。
第三步:验证迁移结果:
# 查看集群Slot分布
redis-cli --cluster check 10.0.1.1:7001
# 确认输出中每个Master负责的Slot数量大致均衡
# 预期:4个Master各约4096个Slot
# 检查迁移后是否有Key遗漏
redis-cli --cluster check 10.0.1.1:7001 --cluster-search-multiple-owners
Redis Cluster缩容操作详解
场景:4主4从缩容为3主3从(移除7006/7007节点)
缩容的顺序和扩容相反:先把目标节点的Slot迁走,再删除空节点。
# 第一步:将目标Master的Slot迁移到其他节点
redis-cli --cluster reshard 10.0.1.1:7001 \
--cluster-slots 4096 \
--cluster-target <接收Slot的Master-Node-ID> \
--cluster-from <待移除Master-Node-ID> \
--cluster-yes
# 第二步:先删除Slave节点(直接删除,无需迁Slot)
redis-cli --cluster del-node 10.0.1.1:7001 <Slave-Node-ID>
# 第三步:删除已清空Slot的Master节点
redis-cli --cluster del-node 10.0.1.1:7001 <待移除Master-Node-ID>
注意:如果目标Master还有Slave,必须先删Slave再删Master。直接删有Slave的Master会导致Slave变成孤节点。
大批量数据迁移的性能优化
默认--cluster reshard的迁移速度是每个管道批量迁移100个Key,对于百万级Key的Slot可能需要数小时。加速方法:
1. 调整管道批量大小
# 源码级调整:修改redis-cli的RESHARD_PIPELINE_SIZE
# 默认值100,改为1000可以10倍提升迁移速度
# 修改src/redis-cli.c中的RESHARD_PIPELINE_SIZE常量
# 重新编译redis-cli
# 或者使用脚本手动控制MIGRATE命令
#!/bin/bash
SRC="10.0.1.1:7001"
DST="10.0.1.16:7006"
SLOT=1000
BATCH=500
while true; do
# 获取该Slot中的Key列表
KEYS=$(redis-cli -h ${SRC%%:*} -p ${SRC##*:} \
CLUSTER GETKEYSINSLOT $SLOT $BATCH)
if [ -z "$KEYS" ]; then
break # Slot已清空
fi
# 批量MIGRATE
for key in $KEYS; do
redis-cli -h ${SRC%%:*} -p ${SRC##*:} \
MIGRATE ${DST%%:*} ${DST##:*} "$key" 0 5000 REPLACE
done
sleep 0.1 # 控制迁移速率,避免影响业务
done
2. 限流迁移避免影响线上业务
MIGRATE命令执行时源节点会短暂阻塞(dump数据期间),Key越大阻塞越久。大Value(超过10KB)的迁移会明显影响同节点其他请求的延迟。解决方法:
# 迁移前检查大Key
redis-cli -h 10.0.1.1 -p 7001 --bigkeys
# 对大Key单独处理:先在业务低峰期手动迁移
# 或者使用UNLINK异步删除+重新写入的方式替代MIGRATE
3. 迁移过程中的客户端重定向开销
Slot迁移期间,客户端对该Slot的请求可能先到源节点,再被ASK重定向到目标节点,多了一次网络往返。如果迁移的Slot对应的是高频访问的Key,客户端延迟会翻倍。优化手段:在客户端维护Slot路由缓存,定期刷新,减少MOVED/ASK重定向次数。Jedis和Lettuce客户端默认支持Slot缓存,但缓存刷新间隔需要根据迁移频率调整:
// Lettuce客户端配置
ClusterTopologyRefreshOptions topologyOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(30)) // 30秒刷新拓扑
.enableAllAdaptiveRefreshTriggers() // 收到MOVED/ASK时也刷新
.adaptiveRefreshTriggersTimeout(Duration.ofSeconds(5))
.build();
RedisClusterClient client = RedisClusterClient.create("redis://10.0.1.1:7001");
client.setOptions(ClusterClientOptions.builder()
.topologyRefreshOptions(topologyOptions)
.build());
扩缩容操作的校验清单
Redis Cluster的扩缩容看似简单,但操作失误后果严重——数据丢失或集群不可用。每次操作后必须执行以下检查:
# 1. 检查集群状态(cluster_state必须为ok)
redis-cli -h 10.0.1.1 -p 7001 CLUSTER INFO | grep cluster_state
# cluster_state:ok
# 2. 检查所有Slot都有归属(没有unassigned Slot)
redis-cli --cluster check 10.0.1.1:7001 2>&1 | grep "unassigned"
# 3. 检查每个Master至少有1个Slave
redis-cli --cluster check 10.0.1.1:7001 2>&1 | grep "replicas"
# 4. 检查内存水位(确保没有节点过载)
for port in 7001 7002 7003 7006; do
echo "Node $port:"
redis-cli -h 10.0.1.1 -p $port INFO memory | grep used_memory_human
done
# 5. 检查客户端连接数是否正常
redis-cli -h 10.0.1.1 -p 7001 INFO clients | grep connected_clients
如果任何一项检查异常,先暂停后续操作排查原因。常见问题:某个Slot的Key迁移不完全(源节点声称迁完了但目标节点没有),用CLUSTER COUNTKEYSINSLOT <slot>在两个节点上分别检查,如果源节点仍然有Key则手动补迁移。
Redis Cluster扩缩容不需要停机,但务必在业务低峰期操作,并且每次只操作一个维度的变更(要么扩要么缩),不要同时做扩容和缩容。操作前后做好数据备份——虽然Redis Cluster有副本,但人为操作失误是不可恢复的。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rediscluster-ji-qun-kuo-suo-rong-yu-shu-ju-qian-yi-shi-zhan/