Redis Cluster集群架构部署与槽位迁移实战

Redis Cluster通过分片机制实现数据水平扩展,将16384个槽位分配到多个主节点,每个主节点负责一部分槽位的数据存储和读写。当单节点内存或吞吐达到瓶颈时,通过增加节点和槽位迁移实现水平扩容。本文讲解Redis Cluster的部署配置和槽位迁移操作。

Redis Cluster架构原理与最小集群部署

Redis Cluster最少需要6个节点(3主3从)保证高可用。主节点负责读写,从节点实时复制主节点数据,主节点故障时从节点自动提升为主节点。客户端通过CRC16算法计算key对应的槽位,直连目标节点。

以6节点集群为例,创建配置文件:

# 为6个节点创建配置(端口7000-7005)
for port in 7000 7001 7002 7003 7004 7005; do
  mkdir -p /data/redis-cluster/${port}
  cat > /data/redis-cluster/${port}/redis.conf << EOF
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
bind 0.0.0.0
protected-mode no
dir /data/redis-cluster/${port}
maxmemory 4gb
maxmemory-policy allkeys-lru
EOF
done

# 启动6个Redis实例
for port in 7000 7001 7002 7003 7004 7005; do
  redis-server /data/redis-cluster/${port}/redis.conf --daemonize yes
done

使用redis-cli创建集群,自动分配槽位和主从关系:

# 创建3主3从集群
redis-cli --cluster create   127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002   127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005   --cluster-replicas 1

# 输出确认槽位分配
# Master[0] -> Slots 0-5460
# Master[1] -> Slots 5461-10922
# Master[2] -> Slots 10923-16383

# 查看集群状态
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster nodes

槽位分配机制与Hash Tag使用

Redis Cluster将16384个槽位平均分配到各主节点。key通过CRC16计算哈希值后对16384取模,确定所属槽位:

# 查看key所在槽位
redis-cli -p 7000 cluster keyslot user:1001
# 返回槽位号,如:(integer) 1280

# 直接操作时,如果连接的节点不持有该槽位会返回MOVED重定向
redis-cli -p 7000 set user:1001 "alice"
# (error) MOVED 1280 127.0.0.1:7000

# 使用-c参数自动处理重定向
redis-cli -c -p 7000 set user:1001 "alice"
# OK

# 查看各节点槽位分布
redis-cli -p 7000 cluster slots

多key操作(MSET、SUNION等)要求所有key在同一槽位。Hash Tag通过在key中使用{}指定哈希计算范围,确保相关key分配到同一槽位:

# 不使用Hash Tag:不同key可能分布在不同节点
redis-cli -c -p 7000 mset user:1001:name alice user:1001:age 30
# (error) CROSSSLOT Keys in request don't hash to the same slot

# 使用Hash Tag:{}内的内容参与哈希计算
redis-cli -c -p 7000 mset {user:1001}:name alice {user:1001}:age 30
# OK

# Hash Tag验证
redis-cli -p 7000 cluster keyslot {user:1001}:name
redis-cli -p 7000 cluster keyslot {user:1001}:age
# 两个key返回相同的槽位号

集群扩容与槽位迁移

当现有节点内存或CPU达到瓶颈时,需要添加新节点并迁移部分槽位。以下演示添加1主1从(端口7006、7007)的扩容过程:

# 启动新节点
for port in 7006 7007; do
  mkdir -p /data/redis-cluster/${port}
  cat > /data/redis-cluster/${port}/redis.conf << EOF
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
bind 0.0.0.0
dir /data/redis-cluster/${port}
EOF
  redis-server /data/redis-cluster/${port}/redis.conf --daemonize yes
done

# 将新主节点加入集群
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# 将新从节点加入集群并指定主节点
NEW_NODE_ID=$(redis-cli -p 7006 cluster nodes | grep myself | awk '{print $1}')
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000   --cluster-slave --cluster-master-id ${NEW_NODE_ID}

新节点加入后没有分配槽位,需要从现有节点迁移部分槽位到新节点:

# 使用redis-cli自动重新分配槽位
redis-cli --cluster rebalance 127.0.0.1:7000   --cluster-use-empty-masters

# 手动迁移指定槽位
redis-cli --cluster reshard 127.0.0.1:7000
# 交互式输入:
# How many slots do you want to move? -> 4096
# What is the receiving node ID? -> 7006的节点ID
# Source node IDs -> all

# 查看迁移后的槽位分布
redis-cli -p 7000 cluster slots

手动迁移单个槽位的底层操作:

# 假设迁移槽位8000从节点7000到节点7006
# 1. 通知目标节点准备导入
redis-cli -p 7006 cluster setslot 8000 importing $(redis-cli -p 7000 cluster nodes | grep myself | awk '{print $1}')

# 2. 通知源节点准备迁移
redis-cli -p 7000 cluster setslot 8000 migrating $(redis-cli -p 7006 cluster nodes | grep myself | awk '{print $1}')

# 3. 迁移槽位中的key
KEYS=$(redis-cli -c -p 7000 cluster getkeysinslot 8000 100)
for key in $KEYS; do
  redis-cli -p 7000 migrate 127.0.0.1 7006 $key 0 5000 REPLACE
done

# 4. 通知所有节点更新槽位归属
for port in 7000 7001 7002 7003 7004 7005 7006 7007; do
  redis-cli -p $port cluster setslot 8000 node $TARGET_ID
done

集群缩容与节点移除

移除节点前需将其槽位迁移到其他节点,再从集群中删除:

# 将待移除节点的槽位迁移到其他节点
redis-cli --cluster reshard 127.0.0.1:7000   --cluster-from $(redis-cli -p 7006 cluster nodes | grep myself | awk '{print $1}')   --cluster-to $(redis-cli -p 7000 cluster nodes | grep myself | awk '{print $1}')   --cluster-slots 4096   --cluster-yes

# 确认待移除节点已无槽位
redis-cli -p 7000 cluster nodes | grep 7006

# 从集群中移除从节点
redis-cli --cluster del-node 127.0.0.1:7007 $(redis-cli -p 7007 cluster nodes | grep myself | awk '{print $1}')

# 从集群中移除主节点
redis-cli --cluster del-node 127.0.0.1:7006 $(redis-cli -p 7006 cluster nodes | grep myself | awk '{print $1}')

故障转移与脑裂防护

主节点故障后,从节点发起选举成为新主节点。cluster-node-timeout控制故障检测超时时间,默认5000ms。超时后从节点认为主节点下线并开始选举。

# 查看集群当前epoch
redis-cli -p 7000 cluster info | grep cluster_current_epoch

# 手动故障转移(计划内维护)
redis-cli -p 7003 cluster failover

# 强制故障转移(主节点不可达时)
redis-cli -p 7003 cluster failover TAKEOVER

# 调整故障检测超时
# cluster-node-timeout 3000

min-replicas配置防止脑裂时主节点继续写入。当可用从节点数低于阈值时,主节点拒绝写入:

# redis.conf
min-replicas-to-write 1
min-replicas-max-lag 10

客户端连接与Pipeline优化

Redis Cluster客户端需要感知集群拓扑,自动处理MOVED和ASK重定向。主流客户端库已内置支持:

// Java Jedis客户端
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.HostAndPort;

Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 7000));
nodes.add(new HostAndPort("127.0.0.1", 7001));
nodes.add(new HostAndPort("127.0.0.1", 7002));

JedisCluster cluster = new JedisCluster(nodes);

// 自动处理重定向
cluster.set("user:1001", "alice");
String value = cluster.get("user:1001");

// Pipeline在Cluster模式下需按节点分组
cluster.pipelined((pipeline) -> {
    pipeline.set("key1", "value1");
    pipeline.set("key2", "value2");
    pipeline.get("key1");
});

Redis Cluster通过槽位分片实现了水平扩展能力,配合主从复制和自动故障转移保障高可用。运维过程中需注意Hash Tag的使用、槽位迁移的在线操作以及故障检测超时参数的合理设置,确保集群稳定运行。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rediscluster-ji-qun-jia-gou-bu-shu-yu-cao-wei-qian-yi-shi/

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

相关推荐