Redis集群 #

一、集群概述 #

1.1 什么是Redis集群 #

Redis集群是Redis的分布式实现:

  • 数据分片:数据分布在多个节点
  • 高可用:每个分片有主从复制
  • 自动故障转移:主节点故障自动切换
text
Redis集群架构:

┌─────────────────────────────────────────────────────────┐
│                    Redis Cluster                       │
│                                                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │
│  │  Master 1   │  │  Master 2   │  │  Master 3   │    │
│  │  槽 0-5460  │  │ 槽 5461-10922│ │槽 10923-16383│   │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘    │
│         │                │                │            │
│  ┌──────┴──────┐  ┌──────┴──────┐  ┌──────┴──────┐    │
│  │  Slave 1    │  │  Slave 2    │  │  Slave 3    │    │
│  └─────────────┘  └─────────────┘  └─────────────┘    │
│                                                         │
│  客户端 ────────────────────────────────────────────▶  │
│         根据键的槽位路由到对应节点                     │
└─────────────────────────────────────────────────────────┘

1.2 集群特点 #

text
Redis集群特点:

┌─────────────────────────────────────────────┐
│ 1. 数据分片                                 │
│    - 16384个槽位                           │
│    - 分布在多个节点                         │
│    - 自动分配                               │
│                                             │
│ 2. 高可用                                   │
│    - 每个分片有主从                         │
│    - 自动故障转移                           │
│    - 最少3主3从                             │
│                                             │
│ 3. 去中心化                                 │
│    - 无中心节点                             │
│    - Gossip协议通信                         │
│    - 每个节点平等                           │
│                                             │
│ 4. 客户端路由                               │
│    - 客户端缓存槽位映射                     │
│    - MOVED重定向                            │
│    - ASK重定向                              │
└─────────────────────────────────────────────┘

二、槽位机制 #

2.1 槽位分配 #

text
Redis集群槽位:

- 总槽位:16384个
- 每个键属于一个槽位
- 槽位分布在多个节点

槽位计算:
CRC16(key) % 16384

示例:
key1 → CRC16(key1) % 16384 = 1234
key2 → CRC16(key2) % 16384 = 5678

2.2 槽位分布 #

text
3主节点槽位分布:

┌─────────────────────────────────────────────┐
│ Master 1: 槽 0 - 5460                      │
│ Master 2: 槽 5461 - 10922                  │
│ Master 3: 槽 10923 - 16383                 │
└─────────────────────────────────────────────┘

每个主节点负责约1/3的槽位

2.3 哈希标签 #

bash
# 哈希标签:确保相关键在同一个槽位

# 使用{}指定哈希标签部分
SET user:{1001}:name "John"
SET user:{1001}:age 25
SET user:{1001}:email "john@example.com"

# 这三个键都在同一个槽位
# 因为只计算{1001}的槽位

# 查看键的槽位
CLUSTER KEYSLOT user:{1001}:name
# (integer) 1234

三、搭建集群 #

3.1 准备节点 #

bash
# 创建6个节点配置文件
# redis-7000.conf
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes

# redis-7001.conf ~ redis-7005.conf 类似
# 只需修改端口号

# 启动6个节点
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

3.2 创建集群 #

bash
# 使用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

# 输出:
# >>> Performing hash slots allocation on 6 nodes...
# Master[0] -> Slots 0 - 5460
# Master[1] -> Slots 5461 - 10922
# Master[2] -> Slots 10923 - 16383
# Adding replica 127.0.0.1:7004 to 127.0.0.1:7000
# Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
# Adding replica 127.0.0.1:7003 to 127.0.0.1:7002

# 输入yes确认

3.3 Docker Compose方式 #

yaml
# docker-compose.yml
version: '3'
services:
  redis-7000:
    image: redis:7.0
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7000
    ports:
      - "7000:7000"
      - "17000:17000"
  
  redis-7001:
    image: redis:7.0
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7001
    ports:
      - "7001:7001"
      - "17001:17001"
  
  redis-7002:
    image: redis:7.0
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7002
    ports:
      - "7002:7002"
      - "17002:17002"
  
  redis-7003:
    image: redis:7.0
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7003
    ports:
      - "7003:7003"
      - "17003:17003"
  
  redis-7004:
    image: redis:7.0
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7004
    ports:
      - "7004:7004"
      - "17004:17004"
  
  redis-7005:
    image: redis:7.0
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7005
    ports:
      - "7005:7005"
      - "17005:17005"

四、集群操作 #

4.1 连接集群 #

bash
# 使用-c选项连接集群
redis-cli -c -p 7000

# 自动重定向
127.0.0.1:7000> SET key1 value1
-> Redirected to slot [9189] located at 127.0.0.1:7001
OK

127.0.0.1:7001> GET key1
"value1"

4.2 查看集群信息 #

bash
# 查看集群信息
CLUSTER INFO

# 输出:
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_slots_pfail:0
# cluster_slots_fail:0
# cluster_known_nodes:6
# cluster_size:3

# 查看集群节点
CLUSTER NODES

# 输出:
# 节点ID 地址 角色 槽位等信息

4.3 查看槽位 #

bash
# 查看槽位分布
CLUSTER SLOTS

# 输出:
# 1) 1) (integer) 0
#    2) (integer) 5460
#    3) 1) "127.0.0.1"
#       2) (integer) 7000
#       3) "node-id"
#    4) 1) "127.0.0.1"
#       2) (integer) 7003
#       3) "replica-node-id"

4.4 添加节点 #

bash
# 添加主节点
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 <node-id>

# 重新分配槽位
redis-cli --cluster reshard 127.0.0.1:7000

4.5 删除节点 #

bash
# 先迁移槽位
redis-cli --cluster reshard 127.0.0.1:7000

# 删除节点
redis-cli --cluster del-node 127.0.0.1:7000 <node-id>

五、故障转移 #

5.1 自动故障转移 #

text
故障转移过程:

┌─────────────────────────────────────────────────────────┐
│ 1. 主节点故障                                           │
│    - 其他节点检测到主节点下线                          │
│    - 标记为FAIL                                        │
├─────────────────────────────────────────────────────────┤
│ 2. 从节点选举                                           │
│    - 从节点发起选举                                    │
│    - 其他主节点投票                                    │
│    - 获得多数票的从节点成为新主节点                    │
├─────────────────────────────────────────────────────────┤
│ 3. 槽位转移                                             │
│    - 新主节点接管槽位                                  │
│    - 更新集群配置                                      │
├─────────────────────────────────────────────────────────┤
│ 4. 客户端更新                                           │
│    - 客户端更新槽位映射                                │
│    - 继续提供服务                                      │
└─────────────────────────────────────────────────────────┘

5.2 手动故障转移 #

bash
# 连接从节点
redis-cli -p 7003

# 手动故障转移
CLUSTER FAILOVER

# 强制故障转移(不等待主节点确认)
CLUSTER FAILOVER FORCE

# 接管故障主节点
CLUSTER FAILOVER TAKEOVER

六、客户端使用 #

6.1 连接集群 #

python
# Python示例
from redis.cluster import RedisCluster

# 连接集群
rc = RedisCluster(
    host='127.0.0.1',
    port=7000,
    decode_responses=True
)

# 使用
rc.set('key', 'value')
value = rc.get('key')

6.2 Java示例 #

java
// Java示例 (Jedis)
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 jedisCluster = new JedisCluster(nodes);

jedisCluster.set("key", "value");
String value = jedisCluster.get("key");

七、集群限制 #

7.1 限制说明 #

text
Redis集群限制:

1. 批量操作限制
   ┌─────────────────────────────────────────────┐
   │ MGET/MSET等批量操作                         │
   │ 只能操作同一个槽位的键                      │
   │ 使用哈希标签解决                            │
   └─────────────────────────────────────────────┘

2. 事务限制
   ┌─────────────────────────────────────────────┐
   │ 事务中的键必须在同一个槽位                  │
   │ 使用哈希标签解决                            │
   └─────────────────────────────────────────────┘

3. Lua脚本限制
   ┌─────────────────────────────────────────────┐
   │ Lua脚本中的键必须在同一个槽位               │
   │ 使用哈希标签解决                            │
   └─────────────────────────────────────────────┘

4. 数据库限制
   ┌─────────────────────────────────────────────┐
   │ 集群只能使用数据库0                         │
   │ 不能使用SELECT命令                          │
   └─────────────────────────────────────────────┘

7.2 解决方案 #

bash
# 使用哈希标签

# 批量操作
MSET user:{1001}:name "John" user:{1001}:age 25

# 事务
MULTI
SET user:{1001}:name "John"
SET user:{1001}:age 25
EXEC

# Lua脚本
EVAL "redis.call('SET', KEYS[1], ARGV[1]); redis.call('SET', KEYS[2], ARGV[2])" 2 user:{1001}:name user:{1001}:age "John" 25

八、最佳实践 #

8.1 集群规模 #

text
集群规模建议:

- 最小:3主3从
- 推荐:5主5从或更多
- 单节点数据量:不超过10GB
- 总数据量:不超过100GB

8.2 网络配置 #

bash
# 配置集群总线端口
# 集群总线端口 = 普通端口 + 10000
# 例如:7000端口的集群总线端口是17000

# 防火墙需要开放两个端口
# 普通端口:7000
# 集群总线端口:17000

8.3 监控指标 #

bash
# 监控集群状态
CLUSTER INFO

# 关注指标
# cluster_state: ok
# cluster_slots_assigned: 16384
# cluster_slots_ok: 16384
# cluster_known_nodes: 6

九、总结 #

集群命令:

命令 说明
CLUSTER INFO 查看集群信息
CLUSTER NODES 查看节点信息
CLUSTER SLOTS 查看槽位分布
CLUSTER KEYSLOT 查看键的槽位
CLUSTER FAILOVER 故障转移

集群特点:

特点 说明
数据分片 16384个槽位
高可用 主从复制+故障转移
去中心化 Gossip协议
自动路由 MOVED/ASK重定向

下一步,让我们学习Redis运维管理!

最后更新:2026-03-27