Redis Cluster集群扩缩容与数据迁移实战操作

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/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐