第七章:Redis Cluster 集群

深入了解 Redis Cluster 的数据分片、节点通信和故障转移机制。

最后更新: 2024-01-15
页面目录

Redis Cluster 集群

Redis Cluster 是 Redis 官方提供的分布式集群解决方案,支持数据分片和自动故障转移。

Cluster 概述

┌─────────────────────────────────────────────────────────────────┐
│                    Redis Cluster 架构                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Client                                                         │
│      │                                                          │
│      ├───────────────────────────────────────────────────────►  │
│      │                                                           │
│   ┌───┴───┐    ┌───┴───┐    ┌───┴───┐    ┌───┴───┐           │
│   │ Slot  │    │ Slot  │    │ Slot  │    │ Slot  │           │
│   │ 0-5460│    │5461-10922│  │10923-16383│ │        │           │
│   └───┬───┘    └───┬───┘    └───┬───┘    └───┬───┘           │
│       │            │            │            │                 │
│   ┌───┴───┐    ┌───┴───┐    ┌───┴───┐    ┌───┴───┐           │
│   │Master1 │    │Master2 │    │Master3 │    │Master4 │           │
│   │Node A  │    │Node B  │    │Node C  │    │Node D  │           │
│   └───┬───┘    └───┬───┘    └───┬───┘    └───┬───┘           │
│       │            │            │            │                 │
│   ┌───┴───┐    ┌───┴───┐    ┌───┴───┐    ┌───┴───┐           │
│   │Replica│    │Replica│    │Replica│    │Replica│           │
│   │(从节点)│    │(从节点)│    │(从节点)│    │(从节点)│           │
│   └───────┘    └───────┘    └───────┘    └───────┘           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Cluster 特性

特性 说明
数据分片 16384 个槽位,自动分布到多个节点
高可用 主从复制 + 自动故障转移
节点通信 Gossip 协议,节点自动发现
写入安全 使用MOVED/ASK重定向
配置一致 客户端可自动更新集群拓扑

槽位机制

16384 个槽位

# 槽位计算公式
slot = CRC16(key) % 16384

# CRC16 校验
# Redis 使用 CRC16(key) mod 16384 计算槽位

槽位分布示例

节点 槽位范围 槽位数量
Node A 0 - 5460 5461
Node B 5461 - 10922 5462
Node C 10923 - 16383 5461

槽位命令

# 查看键的槽位
CLUSTER KEYSLOT mykey

# 查看槽位中的键数量
CLUSTER COUNTKEYSINSLOT 0

# 获取槽位中的键
CLUSTER GETKEYSINSLOT 0 100

创建集群

环境准备

# 创建节点目录
mkdir -p /opt/redis-cluster/{7000,7001,7002,7003,7004,7005}

# 节点配置示例(7000/redis.conf)
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
pidfile /var/run/redis-7000.pid
logfile /var/log/redis-7000.log

启动节点

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

# 验证节点运行
redis-cli -p 7000 PING

创建集群

# 使用 redis-cli 创建集群
redis-cli --cluster create \
  127.0.0.1:7000 \
  127.0.0.1:7001 \
  127.0.0.1:7002 \
  --cluster-replicas 1

# 参数说明:
# --cluster-replicas 1 表示每个主节点配置1个从节点

# 交互式创建
redis-cli --cluster create \
  127.0.0.1:7000 \
  127.0.0.1:7001 \
  127.0.0.1:7002 \
  --cluster-replicas 1

创建流程

1. 检查所有节点是否可用
2. 分配主节点和从节点
3. 分配槽位(从节点自动从属主节点)
4. 输出集群信息确认
5. 完成集群创建

集群命令

节点管理

# 查看集群信息
CLUSTER INFO

# 查看所有节点
CLUSTER NODES

# 查看槽位分配
CLUSTER SLOTS

# 添加节点到集群
CLUSTER MEET ip port

# 忘记节点
CLUSTER FORGET node_id

# 调整槽位
CLUSTER ADDSLOTS slot [slot ...]
CLUSTER DELSLOTS slot [slot ...]
CLUSTER SETSLOT slot MIGRATING node_id
CLUSTER SETSLOT slot IMPORTING node_id

从节点管理

# 将节点设为某主节点的从节点
CLUSTER REPLICATE master_node_id

# 查看节点复制状态
CLUSTER REPLICAS master_node_id

槽位迁移

# 设置槽位迁移源
CLUSTER SETSLOT slot MIGRATING node_id

# 设置槽位导入目标
CLUSTER SETSLOT slot IMPORTING node_id

# 槽位所有权转移
CLUSTER SETSLOT slot node_id

Docker Compose 部署

version: '3.8'
services:
  redis-node1:
    image: redis:7-alpine
    container_name: redis-node1
    ports:
      - "7000:7000"
    command: |
      redis-server --port 7000 
        --cluster-enabled yes 
        --cluster-config-file nodes.conf 
        --cluster-node-timeout 5000
    volumes:
      - redis1-data:/data

  redis-node2:
    image: redis:7-alpine
    container_name: redis-node2
    ports:
      - "7001:7001"
    command: |
      redis-server --port 7001 
        --cluster-enabled yes 
        --cluster-config-file nodes.conf 
        --cluster-node-timeout 5000
    volumes:
      - redis2-data:/data

  redis-node3:
    image: redis:7-alpine
    container_name: redis-node3
    ports:
      - "7002:7002"
    command: |
      redis-server --port 7002 
        --cluster-enabled yes 
        --cluster-config-file nodes.conf 
        --cluster-node-timeout 5000
    volumes:
      - redis3-data:/data

volumes:
  redis1-data:
  redis2-data:
  redis3-data:

客户端连接

客户端要求

  • 支持集群模式
  • 支持 MOVED/ASK 重定向
  • 支持自动发现节点

Python 连接

from redis.cluster import RedisCluster

# 创建集群客户端
rc = RedisCluster(
    host='127.0.0.1',
    port=7000,
    decode_responses=True
)

# 操作(自动路由到正确节点)
rc.set('key1', 'value1')
rc.get('key1')

# 集群操作
rc.info('cluster')

Java 连接

import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.HostAndPort;
import java.util.HashSet;

HashSet<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("key", "value");
cluster.get("key");

故障转移

自动故障转移

1. 主节点不可达
2. 从节点发起选举
3. 从节点升级为主节点
4. 其他节点更新拓扑
5. 客户端自动重定向

手动故障转移

# 在从节点上执行
redis-cli -p 7003 CLUSTER FAILOVER

# 选项
CLUSTER FAILOVER FORCE      # 强制故障转移
CLUSTER FAILOVER TAKEOVER   # 忽略延迟强制转移

数据迁移

在线迁移槽位

# 1. 创建新节点
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# 2. 设置槽位迁移
redis-cli -p 7000 CLUSTER SETSLOT 0 MIGRATING 127.0.0.1:7006

# 3. 在源节点获取键
redis-cli -p 7000 CLUSTER GETKEYSINSLOT 0 100

# 4. 迁移键
redis-cli MIGRATE 127.0.0.1 7006 0 5000 KEYS key1 key2

# 5. 设置槽位归属
redis-cli -p 7006 CLUSTER SETSLOT 0 NODE <new_node_id>

使用 redis-cli 迁移

# 迁移槽位 0-1000 到新节点
redis-cli --cluster reshard \
  127.0.0.1:7000 \
  --cluster-from <source_node_id> \
  --cluster-to <target_node_id> \
  --cluster-slots 1000 \
  --cluster-yes

集群扩缩容

扩容

# 1. 添加新节点
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 <node_id>

# 3. 迁移槽位
redis-cli --cluster reshard 127.0.0.1:7000

缩容

# 1. 迁移槽位到其他节点
redis-cli --cluster reshard 127.0.0.1:7000

# 2. 删除从节点
redis-cli --cluster del-node 127.0.0.1:7000 <node_id>

# 3. 删除主节点(先确保槽位已迁出)
redis-cli --cluster del-node 127.0.0.1:7000 <node_id>

集群状态

查看集群信息

# 集群状态
CLUSTER INFO
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_known_nodes:6
# cluster_size:3

# 节点详情
CLUSTER NODES
# node_id master_a 127.0.0.1:7000 master - 0-5460 connected
# node_id slave_b 127.0.0.1:7003 slave master_a 0 connected

状态说明

状态 说明
OK 集群正常
FAIL 集群不可用
PFAIL 节点疑似下线
LOADING 节点正在加载数据

常见问题

1. 集群不可用

# 检查节点状态
redis-cli -p 7000 CLUSTER INFO

# 检查所有节点
redis-cli -p 7000 CLUSTER NODES

2. 槽位未完全分配

# 查看未分配的槽位
redis-cli -p 7000 CLUSTER SLOTS

# 分配槽位
redis-cli -p 7000 CLUSTER ADDSLOTS 0 1 2 3 ...

3. 节点间无法通信

# 检查端口
nc -zv 127.0.0.1 7000
nc -zv 127.0.0.1 7001

# 检查防火墙
iptables -L

最佳实践

# 集群配置建议
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-replica-validity-factor 10
cluster-migration-barrier 1
配置项 推荐值 说明
cluster-node-timeout 15000 节点超时时间(毫秒)
cluster-replica-validity-factor 10 从节点有效因子
cluster-migration-barrier 1 迁移屏障

下一步

接下来让我们学习 Redis Sentinel 哨兵模式。

👉 哨兵模式