Redis Cluster集群架构与槽位分配故障转移配置实战

Redis Cluster是Redis官方提供的分布式方案,通过数据分片实现水平扩展,通过主从复制保障高可用。集群将所有数据划分为16384个槽位(slot),每个节点负责一部分槽位。写入数据时根据CRC16算法计算key的槽位号,路由到对应节点。当节点故障时,其从节点自动提升为主节点接管槽位,实现自动故障转移。本文从集群搭建到故障转移配置,完整演示Redis Cluster的生产级部署。

Redis Cluster数据分片与槽位映射原理

Redis Cluster采用哈希分片策略。key到slot的映射公式:slot = CRC16(key) mod 16384。CRC16算法对key的每个字节计算,生成16位哈希值,对16384取模得到槽位号。每个节点维护一份cluster slots映射表,记录哪些槽位属于哪个节点。

客户端可以连接任意节点发起请求。如果key所在槽位不在当前节点,节点返回MOVED重定向响应,包含目标节点地址。客户端根据MOVED响应更新本地槽位映射缓存,后续请求直接发送到正确节点。Smart Client(如Jedis Cluster、Lettuce)在初始化时拉取完整槽位映射表,运行期自动维持缓存同步,大幅减少重定向开销。

当多个key分布在不同槽位时,跨槽位操作(MGET、SUNION等)会报错。Redis Cluster通过Hash Tag机制支持多key操作——key中{…}包裹的部分参与哈希计算,如user:{1001}:name和user:{1001}:age映射到同一槽位,可以批量操作。

集群搭建与节点配置

最小Redis Cluster需要6个节点(3主3从)。以Docker方式搭建6节点集群:

# 每个节点的redis.conf基础配置
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
# docker-compose.yml 创建6个Redis节点
version: "3.8"
services:
  redis-7000:
    image: redis:7.2
    command: redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7000:7000"]
  redis-7001:
    image: redis:7.2
    command: redis-server --port 7001 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7001:7001"]
  redis-7002:
    image: redis:7.2
    command: redis-server --port 7002 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7002:7002"]
  redis-7003:
    image: redis:7.2
    command: redis-server --port 7003 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7003:7003"]
  redis-7004:
    image: redis:7.2
    command: redis-server --port 7004 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7004:7004"]
  redis-7005:
    image: redis:7.2
    command: redis-server --port 7005 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7005:7005"]

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

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

# --cluster-replicas 1 表示每个主节点1个从节点
# 集群自动分配:
# 7000(M) -> 7003(S)
# 7001(M) -> 7004(S)
# 7002(M) -> 7005(S)
# 槽位分配:0-5460(7000), 5461-10922(7001), 10923-16383(7002)

集群状态检查与槽位管理命令

# 查看集群信息
redis-cli -p 7000 cluster info
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_known_nodes:6
# cluster_size:3

# 查看节点列表
redis-cli -p 7000 cluster nodes
# 输出格式:ID IP:PORT@CPORT flags master-id ping pong epoch link

# 查看槽位分配
redis-cli -p 7000 cluster slots

# 检查集群一致性
redis-cli --cluster check 127.0.0.1:7000

# 查看key所在槽位
redis-cli -p 7000 cluster keyslot mykey
# (integer) 5474

在线扩容:添加节点与槽位迁移

向集群添加新节点时,需要将部分槽位从现有节点迁移到新节点,整个过程在线进行不影响业务。

# 1. 添加新主节点( initially无槽位)
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# 2. 为新主节点添加从节点
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id <7006节点ID>

# 3. 重新分片,从现有3个主节点各迁移部分槽位到新节点
redis-cli --cluster reshard 127.0.0.1:7000 \
  --cluster-from <7000节点ID>,<7001节点ID>,<7002节点ID> \
  --cluster-to <7006节点ID> \
  --cluster-slots 4096 \
  --cluster-yes

# 4. 验证槽位分布
redis-cli --cluster check 127.0.0.1:7000

槽位迁移过程中,每个key的迁移是原子操作——源节点将key序列化发送到目标节点,目标节点确认后源节点删除本地副本。迁移期间对该key的请求由源节点代理转发到目标节点,客户端无感知。cluster-require-full-coverage默认为yes,即任意节点故障导致槽位不可达时整个集群不可写。生产环境可设为no,允许部分槽位不可用时其他槽位正常服务。

故障检测与自动故障转移机制

Redis Cluster通过Gossip协议进行节点间通信和故障检测。每个节点定期向其他节点发送PING消息,收到PONG响应确认存活。cluster-node-timeout参数控制超时阈值(默认15秒,生产环境推荐5-10秒),超过该时间未收到响应则将目标节点标记为PFAIL(疑似故障)。

PFAIL状态需要经过集群多数派确认才升级为FAIL(确定故障)。当主节点被标记为FAIL后,其从节点发起故障转移:

1. 从节点检测到主节点FAIL状态

2. 从节点等待一段随机延迟(避免多个从节点同时竞选),延迟时间与从节点复制偏移量相关——偏移量越大(数据越新)延迟越短

3. 从节点向集群发起选举请求,获取多数派主节点投票

4. 赢得选举的从节点执行SLAVEOF NO ONE升级为主节点

5. 新主节点广播PONG消息通知集群槽位归属变更

# 手动故障转移(计划性维护)
redis-cli -p 7003 cluster failover
# 7003为从节点,执行后它将替代主节点

# 手动故障转移可选模式:
# cluster failover takeover - 强制接管,不经过选举(紧急恢复用)
# cluster failover force - 跳过主节点确认直接选举

# 查看故障转移后拓扑
redis-cli -p 7000 cluster nodes

客户端连接与读写分离配置

以Java Lettuce客户端为例配置Redis Cluster连接:

// Spring Boot application.yml
spring:
  data:
    redis:
      cluster:
        nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002
        max-redirects: 3
      timeout: 3000ms
      lettuce:
        pool:
          max-active: 16
          max-idle: 8
          min-idle: 2
        # 开启读写分离(从节点读取)
        read-from: REPLICA_PREFERRED
// RedisTemplate配置
@Configuration
public class RedisClusterConfig {

    @Bean
    public RedisTemplate redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setEnableTransactionSupport(false);
        return template;
    }
}

read-from=REPLICA_PREFERRED优先从从节点读取,主节点仅在无可用从节点时使用。读写分离适用于读多写少且能容忍主从延迟的场景。需要注意从节点的数据存在复制延迟(通常毫秒级),对强一致性要求高的读操作应从主节点读取(用READONLY命令标记后从节点也会返回数据,但可能是旧数据)。

max-redirects=3设置MOVED和ASK重定向的最大次数。超过重定向次数仍无法到达正确节点时抛出异常。正常情况下Smart Client维持本地槽位映射缓存,重定向仅在集群拓扑变更时偶发,3次够用。

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

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

相关推荐

Redis Cluster集群架构与槽位分配故障转移配置实战

Redis Cluster是Redis官方提供的分布式方案,通过数据分片实现水平扩展,通过主从复制保障高可用。集群将所有数据划分为16384个槽位(slot),每个节点负责一部分槽位。写入数据时根据CRC16算法计算key的槽位号,路由到对应节点。当节点故障时,其从节点自动提升为主节点接管槽位,实现自动故障转移。本文从集群搭建到故障转移配置,完整演示Redis Cluster的生产级部署。

Redis Cluster数据分片与槽位映射原理

Redis Cluster采用哈希分片策略。key到slot的映射公式:slot = CRC16(key) mod 16384。CRC16算法对key的每个字节计算,生成16位哈希值,对16384取模得到槽位号。每个节点维护一份cluster slots映射表,记录哪些槽位属于哪个节点。

客户端可以连接任意节点发起请求。如果key所在槽位不在当前节点,节点返回MOVED重定向响应,包含目标节点地址。客户端根据MOVED响应更新本地槽位映射缓存,后续请求直接发送到正确节点。Smart Client(如Jedis Cluster、Lettuce)在初始化时拉取完整槽位映射表,运行期自动维持缓存同步,大幅减少重定向开销。

当多个key分布在不同槽位时,跨槽位操作(MGET、SUNION等)会报错。Redis Cluster通过Hash Tag机制支持多key操作——key中{…}包裹的部分参与哈希计算,如user:{1001}:name和user:{1001}:age映射到同一槽位,可以批量操作。

集群搭建与节点配置

最小Redis Cluster需要6个节点(3主3从)。以Docker方式搭建6节点集群:

# 每个节点的redis.conf基础配置
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
# docker-compose.yml 创建6个Redis节点
version: "3.8"
services:
  redis-7000:
    image: redis:7.2
    command: redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7000:7000"]
  redis-7001:
    image: redis:7.2
    command: redis-server --port 7001 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7001:7001"]
  redis-7002:
    image: redis:7.2
    command: redis-server --port 7002 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7002:7002"]
  redis-7003:
    image: redis:7.2
    command: redis-server --port 7003 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7003:7003"]
  redis-7004:
    image: redis:7.2
    command: redis-server --port 7004 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7004:7004"]
  redis-7005:
    image: redis:7.2
    command: redis-server --port 7005 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    ports: ["7005:7005"]

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

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

# --cluster-replicas 1 表示每个主节点1个从节点
# 集群自动分配:
# 7000(M) -> 7003(S)
# 7001(M) -> 7004(S)
# 7002(M) -> 7005(S)
# 槽位分配:0-5460(7000), 5461-10922(7001), 10923-16383(7002)

集群状态检查与槽位管理命令

# 查看集群信息
redis-cli -p 7000 cluster info
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_known_nodes:6
# cluster_size:3

# 查看节点列表
redis-cli -p 7000 cluster nodes
# 输出格式:ID IP:PORT@CPORT flags master-id ping pong epoch link

# 查看槽位分配
redis-cli -p 7000 cluster slots

# 检查集群一致性
redis-cli --cluster check 127.0.0.1:7000

# 查看key所在槽位
redis-cli -p 7000 cluster keyslot mykey
# (integer) 5474

在线扩容:添加节点与槽位迁移

向集群添加新节点时,需要将部分槽位从现有节点迁移到新节点,整个过程在线进行不影响业务。

# 1. 添加新主节点( initially无槽位)
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# 2. 为新主节点添加从节点
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id <7006节点ID>

# 3. 重新分片,从现有3个主节点各迁移部分槽位到新节点
redis-cli --cluster reshard 127.0.0.1:7000 \
  --cluster-from <7000节点ID>,<7001节点ID>,<7002节点ID> \
  --cluster-to <7006节点ID> \
  --cluster-slots 4096 \
  --cluster-yes

# 4. 验证槽位分布
redis-cli --cluster check 127.0.0.1:7000

槽位迁移过程中,每个key的迁移是原子操作——源节点将key序列化发送到目标节点,目标节点确认后源节点删除本地副本。迁移期间对该key的请求由源节点代理转发到目标节点,客户端无感知。cluster-require-full-coverage默认为yes,即任意节点故障导致槽位不可达时整个集群不可写。生产环境可设为no,允许部分槽位不可用时其他槽位正常服务。

故障检测与自动故障转移机制

Redis Cluster通过Gossip协议进行节点间通信和故障检测。每个节点定期向其他节点发送PING消息,收到PONG响应确认存活。cluster-node-timeout参数控制超时阈值(默认15秒,生产环境推荐5-10秒),超过该时间未收到响应则将目标节点标记为PFAIL(疑似故障)。

PFAIL状态需要经过集群多数派确认才升级为FAIL(确定故障)。当主节点被标记为FAIL后,其从节点发起故障转移:

1. 从节点检测到主节点FAIL状态

2. 从节点等待一段随机延迟(避免多个从节点同时竞选),延迟时间与从节点复制偏移量相关——偏移量越大(数据越新)延迟越短

3. 从节点向集群发起选举请求,获取多数派主节点投票

4. 赢得选举的从节点执行SLAVEOF NO ONE升级为主节点

5. 新主节点广播PONG消息通知集群槽位归属变更

# 手动故障转移(计划性维护)
redis-cli -p 7003 cluster failover
# 7003为从节点,执行后它将替代主节点

# 手动故障转移可选模式:
# cluster failover takeover - 强制接管,不经过选举(紧急恢复用)
# cluster failover force - 跳过主节点确认直接选举

# 查看故障转移后拓扑
redis-cli -p 7000 cluster nodes

客户端连接与读写分离配置

以Java Lettuce客户端为例配置Redis Cluster连接:

// Spring Boot application.yml
spring:
  data:
    redis:
      cluster:
        nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002
        max-redirects: 3
      timeout: 3000ms
      lettuce:
        pool:
          max-active: 16
          max-idle: 8
          min-idle: 2
        # 开启读写分离(从节点读取)
        read-from: REPLICA_PREFERRED
// RedisTemplate配置
@Configuration
public class RedisClusterConfig {

    @Bean
    public RedisTemplate redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setEnableTransactionSupport(false);
        return template;
    }
}

read-from=REPLICA_PREFERRED优先从从节点读取,主节点仅在无可用从节点时使用。读写分离适用于读多写少且能容忍主从延迟的场景。需要注意从节点的数据存在复制延迟(通常毫秒级),对强一致性要求高的读操作应从主节点读取(用READONLY命令标记后从节点也会返回数据,但可能是旧数据)。

max-redirects=3设置MOVED和ASK重定向的最大次数。超过重定向次数仍无法到达正确节点时抛出异常。正常情况下Smart Client维持本地槽位映射缓存,重定向仅在集群拓扑变更时偶发,3次够用。

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

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

相关推荐