Redis Cluster集群部署实战:槽位分配与故障转移机制详解

Redis Cluster是Redis官方提供的分布式方案,通过槽位(Slot)分区实现数据分片,支持自动故障转移和在线扩缩。与哨兵模式不同,Cluster模式无中心节点,每个节点都存储完数据的子集,客户端可连接任意节点,节点间通过Gossip协议同步集群状态。

Redis Cluster槽位分配原理

Redis Cluster将数据划分为16384个槽位,每个节点负责一部分槽位。键到槽位的映射使用CRC16算法,公式为 slot = CRC16(key) mod 16384。节点数变化时,槽位在节点间迁移,但总槽位数始终为16384。

# 创建6节点集群(3主3从)
# 节炱1: 7000(主) 7001(从)
# 节炲2: 7002(主) 7003(从)
# 节炲3: 7004(主) 7005(从)

# 节炱1配置文件 redis-7000.conf
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec

# 启动所有节点
redis-server redis-7000.conf
redis-server redis-7001.conf
redis-server redis-7002.conf
redis-server redis-7003.conf
redis-server redis-7004.conf
redis-server redis-7005.conf

# 创建集群
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

# 查看集群状态
redis-cli -p 7000 cluster nodes
# 输出:
# id 7000 master - 0-5460 slots
# id 7002 master - 5461-10922 slots
# id 7004 master - 10923-16383 slots
# id 7001 slave of 7000
# id 7003 slave of 7002
# id 7005 slave of 7004

客户端连接与MOVED重定向

# 客户端直接连接某个节点
redis-cli -p 7000
> SET user:1001 "hello"
# 如果key不在该节点的槽位范围,返回MOVED错误
# (error) MOVED 5798 127.0.0.1:7002
# 表示slot 5798在节炲7002上

# 使用-c参数启用集群模式(自动MOVED重定向)
redis-cli -c -p 7000
> SET user:1001 "hello"
# -> Redirected to slot [5798] located at 127.0.0.1:7002
# OK

# Java客户端连接示例
import redis.clients.jedis.*;

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

JedisCluster cluster = new JedisCluster(
    nodes,
    5000,  // 连接超时
    10,    // 重试次数
    new GenericObjectPoolConfig<>()
);

cluster.set("user:1001", "hello");
String val = cluster.get("user:1001");
// JedisCluster自动处理MOVED重定向和连接池

故障转移机制详解

当某个主节点故障,Cluster需要将其上的槽位转移到对应的从节点。转移过程分为此步:检测故障、确认下线、提升从节点、广播状态。

# 模拟主节炲7000故障
redis-cli -p 7000 DEBUG sleep 10
# 等待cluster-node-timeout(5秒)96后,其他节点标记它为PFAIL
# 再经过一个timeout周期后,标记为FAIL
# 从节炲7001发起选举,提升为主节点

# 查看转移后的状态
redis-cli -p 7002 cluster nodes
# 原从节炲7001已成为主节炲
# 原主节炲7000标记为fail

# 故障恢复后重新加入集群
redis-server redis-7000.conf
redis-cli --cluster add-node 127.0.0.1:7000 127.0.0.1:7002 --cluster-slave --cluster-master-id <node7001_id>
# 7000作为7001(现主)的从节点重新加入

扩缩节点与槽位迁移

# 添加新节炲(7006主 7007从)
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id <node7006_id>

# 分配槽位到新节炲
redis-cli --cluster reshard 127.0.0.1:7000
# How many slots? 4096
# Receiving node ID? <node7006_id>
# Source node ID? all
# 从所有现有主节炲均分槽位给新节炲

# 查看槽位分配
redis-cli -p 7000 cluster slots
# 1) 1) (integer) 0
#    2) (integer) 4095
#    3) 1) "127.0.0.1" 2) (integer) 7006  # 新节炲分担的槽位
# 2) 1) (integer) 4096
#    2) (integer) 8191
#    3) 1) "127.0.0.1" 2) (integer) 7000
# ...

# 使用redis-cli自动均衡槽位
redis-cli --cluster rebalance 127.0.0.1:7000 --cluster-threshold 1 --cluster-simulate

Spring Boot集成Redis Cluster

# application.yml
spring:
  redis:
    cluster:
      nodes:
        - 192.168.1.10:7000
        - 192.168.1.10:7001
        - 192.168.1.11:7002
        - 192.168.1.11:7003
        - 192.168.1.12:7004
        - 192.168.1.12:7005
      max-redirects: 3
    lettuce:
      pool:
        max-active: 16
        max-idle: 8
        min-idle: 2
      cluster:
        refresh:
          adaptive: true
          period: 30s

// Java配置
@Configuration
public class RedisClusterConfig {
    
    @Bean
    public LettuceConnectionFactory redisConnectionFactory(
            RedisClusterConfiguration clusterConfig) {
        clusterConfig.setMaxRedirects(3);
        
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
            .readFrom(ReadFrom.REPLICA_PREFERRED)  // 读操作优先读从节炲
            .commandTimeout(Duration.ofSeconds(3))
            .build();
        
        return new LettuceConnectionFactory(clusterConfig, clientConfig);
    }
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

Redis Cluster的设计理念是去中心化,每个节点都能独立服务。槽位机制使得数据分片对客户端透明,客户端可连接任意节点并通过MOVED重定向找到目标节点。生产环境建议至少6个节炲(3主3从),不同机房部署避免单机架集故障。应用层需处理好跨槽位的多键操作,使用hash tag(如{user:1001}:name、{user:1001}:age)确保相关键落在同一槽位。

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

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

相关推荐