第七章: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 哨兵模式。
👉 哨兵模式