前言
当单机 Redis 无法满足业务需求时,就需要引入集群方案。Redis 提供了三种主要的集群模式:主从复制、哨兵模式和 Cluster 集群。本文将系统讲解三种方案的原理、搭建和适用场景。
一、主从复制
1.1 架构
┌──────────────┐
│ Master │
│ (读+写) │
└──────┬───────┘
│ 复制
┌──────────┼──────────┐
│ │ │
┌──────▼───┐ ┌───▼────┐ ┌──▼─────┐
│ Slave 1 │ │Slave 2 │ │Slave 3 │
│ (只读) │ │(只读) │ │(只读) │
└──────────┘ └────────┘ └────────┘1.2 工作原理
- 全量同步:Slave 首次连接 Master 时,Master 执行 BGSAVE 生成 RDB 文件,发送给 Slave
- 增量同步:全量同步完成后,Master 将新的写命令实时同步给 Slave
- 断线重连:Slave 断线后重连,通过 replid + offset 判断是否可以增量同步
1.3 搭建配置
# slave1.conf
port 6380
# 配置主节点
slaveof 192.168.1.10 6379
# 从节点只读
slave-read-only yes
# 主节点密码
masterauth your_password# 启动从节点
redis-server slave1.conf
# 验证主从关系
redis-cli -p 6380 INFO replication
# role:slave
# master_host:192.168.1.10
# master_port:63791.4 优缺点
| 优点 | 缺点 |
|---|---|
| 配置简单 | Master 宕机需手动切换 |
| 读写分离,提升读性能 | 不具备自动故障转移 |
| 数据有副本 | 全量同步时可能阻塞 Master |
二、哨兵模式(Sentinel)
2.1 架构
┌──────────┐ ┌──────────┐ ┌──────────┐
│Sentinel 1│ │Sentinel 2│ │Sentinel 3│
│ (监控) │ │ (监控) │ │ (监控) │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└──────┬───────┴──────┬──────┘
│ │
┌──────▼──────┐ ┌────▼─────┐
│ Master │ │ Slave │
│ (读+写) │ │ (只读) │
└─────────────┘ └──────────┘2.2 工作原理
- 监控:Sentinel 不断向 Master/Slave 发送 PING 命令
- 主观下线:某个 Sentinel 发现节点无响应,标记为主观下线
- 客观下线:超过半数 Sentinel 都报告节点下线,标记为客观下线
- 选举 Leader:Sentinel 之间选举一个 Leader 执行故障转移
- 故障转移:Leader 选一个 Slave 提升为新 Master,通知其他 Slave 和客户端
2.3 搭建配置
# sentinel1.conf
port 26379
# 监控的 Master(名称 IP 端口 仲裁人数)
sentinel monitor mymaster 192.168.1.10 6379 2
# Master 无响应 30 秒判定下线
sentinel down-after-milliseconds mymaster 30000
# 故障转移超时时间
sentinel failover-timeout mymaster 180000
# 同时只允许1个Slave做同步
sentinel parallel-syncs mymaster 1
# Master 密码
sentinel auth-pass mymaster your_password# 启动3个Sentinel
redis-sentinel sentinel1.conf
redis-sentinel sentinel2.conf
redis-sentinel sentinel3.conf2.4 故障转移过程
1. Master宕机
│
2. Sentinels检测到Master无响应
│
3. 超过quorum(2)个Sentinel标记为客观下线
│
4. 选举Leader Sentinel
│
5. Leader选择最优Slave提升为Master:
- 排除故障Slave
- 选择offset最大的Slave(数据最新)
- 优先级高的Slave优先
│
6. 其他Slave指向新Master
│
7. 通知客户端新Master地址
│
8. 旧Master恢复后变为Slave2.5 客户端连接
// PHP 客户端连接 Sentinel
$sentinels = [
'tcp://192.168.1.10:26379',
'tcp://192.168.1.11:26379',
'tcp://192.168.1.12:26379',
];
$redis = new RedisSentinel($sentinels, [
'name' => 'mymaster',
'password' => 'your_password',
]);
// 自动路由到当前 Master
$redis->set('key', 'value');三、Cluster 集群
3.1 架构
┌─────────────────────────────────────────────────────┐
│ Redis Cluster │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node A │ │ Node B │ │ Node C │ │
│ │Master │ │Master │ │Master │ │
│ │槽0-5460 │ │槽5461- │ │槽10923- │ │
│ │ │ │ 10922 │ │ 16383 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │
│ │ Node A' │ │ Node B' │ │ Node C' │ │
│ │ Slave │ │ Slave │ │ Slave │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────┘3.2 核心概念
哈希槽(Hash Slot)
Redis Cluster 有 16384 个哈希槽,分布在所有 Master 节点上:
# 计算key属于哪个槽
slot = CRC16(key) % 16384
# 示例
# key="user:1001" → CRC16 → slot=12345
# slot 12345 属于 Node C (10923-16383)节点通信(Gossip协议)
每个节点定期向其他节点发送 PING 消息,交换集群状态信息。
3.3 搭建 Cluster
方式一:手动搭建(6节点,3主3从)
# 创建6个配置文件
for port in 7001 7002 7003 7004 7005 7006; do
mkdir -p /redis/cluster/$port
cat > /redis/cluster/$port/redis.conf << EOF
port $port
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
dir /redis/cluster/$port
EOF
done
# 启动6个节点
for port in 7001 7002 7003 7004 7005 7006; do
redis-server /redis/cluster/$port/redis.conf &
done
# 创建集群
redis-cli --cluster create \
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 127.0.0.1:7006 \
--cluster-replicas 1方式二:Docker Compose 搭建
version: '3.8'
services:
redis-node-1:
image: redis:7
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7001
ports:
- "7001:7001"
networks:
- redis-cluster
redis-node-2:
image: redis:7
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7002
ports:
- "7002:7002"
networks:
- redis-cluster
# ... node-3 到 node-6 同理
redis-cluster-init:
image: redis:7
command: >
bash -c "sleep 10 &&
echo yes | redis-cli --cluster create
redis-node-1:7001 redis-node-2:7002 redis-node-3:7003
redis-node-4:7004 redis-node-5:7005 redis-node-6:7006
--cluster-replicas 1"
depends_on:
- redis-node-1
- redis-node-2
- redis-node-3
- redis-node-4
- redis-node-5
- redis-node-6
networks:
- redis-cluster
networks:
redis-cluster:
driver: bridge3.4 客户端使用
// PHP 使用 Redis Cluster
$redis = new RedisCluster(
null, // null 表示自动发现节点
[
'127.0.0.1:7001',
'127.0.0.1:7002',
'127.0.0.1:7003',
],
2, // 连接超时
2, // 读写超时
true, // 持久化连接
'password'
);
// 使用方式与单机一致,客户端自动路由
$redis->set('user:1001', 'Alice');
$redis->set('user:1002', 'Bob');
$redis->set('user:1003', 'Charlie');
// 不同的key可能落在不同节点
// user:1001 → slot 12345 → Node C
// user:1002 → slot 6789 → Node B
// user:1003 → slot 456 → Node A3.5 Hash Tag
如果需要让多个 key 落在同一个槽,使用 Hash Tag:
# 用 {} 指定hash计算的部分
SET {user:1001}:profile "Alice's profile"
SET {user:1001}:settings '{"theme":"dark"}'
SET {user:1001}:cart "[]"
# 三个key都计算 user:1001 的CRC16,落在同一个槽
# 可以在同一节点执行批量操作
MGET {user:1001}:profile {user:1001}:settings {user:1001}:cart四、三种方案对比
| 特性 | 主从复制 | Sentinel 哨兵 | Cluster 集群 |
|---|---|---|---|
| 数据分片 | 否 | 否 | 是(16384槽) |
| 自动故障转移 | 否 | 是 | 是 |
| 读写分离 | 是 | 是 | 是 |
| Master单点瓶颈 | 是 | 是 | 否 |
| 最少节点数 | 2 | 3+Sentinel | 6 |
| 复杂度 | 低 | 中 | 高 |
| 适用场景 | 读多写少 | 中小规模 | 大规模 |
五、选型建议
数据量 < 10GB?
├── 是 → 单机Redis够用
│ └── 需要高可用?
│ ├── 是 → Sentinel(3节点+3哨兵)
│ └── 否 → 单机
│
└── 否 → 数据量大/并发高
└── Redis Cluster(3主3从起步)生产环境推荐
- 中小项目:Sentinel 哨兵(1主2从+3哨兵)
- 大型项目:Redis Cluster(3主3从起步,按需扩展)
- 极大规模:Cluster + 多机房部署 + 代理层
六、运维注意事项
6.1 内存监控
# 查看各节点内存使用
redis-cli -p 7001 INFO memory | grep used_memory_human
redis-cli -p 7002 INFO memory | grep used_memory_human
redis-cli -p 7003 INFO memory | grep used_memory_human
# 集群整体状态
redis-cli -p 7001 CLUSTER INFO
redis-cli -p 7001 CLUSTER NODES6.2 扩容(Cluster)
# 新增节点
redis-server /redis/cluster/7007/redis.conf
# 加入集群
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001
# 分配槽位(从现有节点迁移部分槽到新节点)
redis-cli --cluster reshard 127.0.0.1:7001 \
--cluster-from <现有节点ID> \
--cluster-to <新节点ID> \
--cluster-slots 1000 \
--cluster-yes6.3 数据迁移
# 在线迁移(不停服)
redis-cli --cluster rebalance 127.0.0.1:7001 \
--cluster-use-empty-masters \
--cluster-threshold 1总结
| 方案 | 核心价值 | 关键限制 |
|---|---|---|
| 主从复制 | 读写分离、数据备份 | 无自动故障转移 |
| Sentinel | 自动故障转移、高可用 | 单Master写入瓶颈 |
| Cluster | 数据分片、水平扩展 | 不支持跨槽事务、复杂度高 |
选择原则:先评估数据量和并发量,小规模用 Sentinel,大规模用 Cluster,不要过度设计。
评论 (0)