Redis集群高可用:从主从复制到Cluster模式生产实战
**作者:洛水石** | **更新日期:2026-05-11** | **标签:Redis | 集群 | 高可用 | 哨兵模式 | Cluster**
前言
凌晨2点,被电话吵醒:Redis从节点宕机,业务缓存失效,数据库被打爆。赶紧爬起来处理,手忙脚乱地重启服务。
这不是故事,是很多团队的常态。**Redis没有高可用,就像定时炸弹一样**。
今天系统性地讲清楚Redis的高可用方案:主从复制 → 哨兵模式 → Cluster分片,从原理到生产配置,手把手教你搭建真正可靠的Redis集群。
一、高可用架构演进
1.1 三种模式对比
模式 | 原理 | 适用场景 | 复杂度 |
**主从复制** | Master写,Slave读 | 读多写少、读写分离 | 低 |
**哨兵模式** | 主从 + 自动故障转移 | 中小型、要求自动切换 | 中 |
**Cluster模式** | 数据分片 + 多主 | 大数据量、高并发 | 高 |
1.2 主从复制原理
▲ 图1:Redis主从复制架构
**复制流程**:
- Slave向Master发送SYNC命令
- Master执行BGSAVE生成RDB文件
- Master将RDB文件发送给Slave
- Slave加载RDB文件
- 后续增量复制(Command Stream)
二、主从复制配置
2.1 Docker快速搭建
# 创建主节点
docker run -d --name redis-master \
-p 6379:6379 \
-v redis_master_data:/data \
redis:7.2-alpine \
redis-server --requirepass master123
# 创建从节点1
docker run -d --name redis-slave1 \
-p 6380:6379 \
-v redis_slave1_data:/data \
redis:7.2-alpine \
redis-server --replicaof redis-master 6379 \
--masterauth master123
# 创建从节点2
docker run -d --name redis-slave2 \
-p 6381:6379 \
-v redis_slave2_data:/data \
redis:7.2-alpine \
redis-server --replicaof redis-master 6379 \
--masterauth master123
2.2 配置文件方式
# redis.conf - Master配置
bind 0.0.0.0
port 6379
requirepass master123
daemonize no
loglevel notice
dir /data
appendonly yes
appendfilename "appendonly.aof"
# 从节点配置
replicaof <master-ip> 6379
masterauth master123
replica-serve-stale-data yes
replica-read-only yes
2.3 验证主从状态
# 查看主节点信息
redis-cli -h localhost -p 6379 -a master123 INFO replication
# 输出
role:master
connected_slaves:2
slave0:ip=172.17.0.2,port=6379,state=online,offset=12345
slave1:ip=172.17.0.3,port=6379,state=online,offset=12345
# 从节点查看
redis-cli -h localhost -p 6380 INFO replication
# role:replica
# master_host:172.17.0.1
# master_port:6379
三、哨兵模式配置
3.1 哨兵工作原理
┌─────────────┐
│ Client │
└──────┬──────┘
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐
│Sentinel│ │Sentinel│ │Sentinel│ ← 哨兵集群(奇数个)
│ 1 │ │ 2 │ │ 3 │
└───┬───┘ └───┬───┘ └───┬───┘
│ │ │
└──────────┼──────────┘
│ 监控/选举
┌──────────┴──────────┐
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ Master │ ←──────→ │ Slave1 │
└─────────┘ └─────────┘
│
▼
┌─────────┐
│ Slave2 │
└─────────┘
**故障转移流程**:
- 哨兵检测Master心跳超时
- 哨兵集群投票决定是否故障转移
- 选举一个从节点升级为新Master
- 其他从节点切换到新Master
- 通知应用客户端
3.2 哨兵配置文件
# sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster master123
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel announce-ip "192.168.1.101"
sentinel announce-port 26379
**关键参数说明**:
参数 | 说明 | 推荐值 |
`monitor` | 监控的主节点 | `quorum`设2~3 |
`down-after-ms` | 主观下线时间 | 30秒 |
`parallel-syncs` | 并行同步数 | 1(避免雪崩) |
`failover-timeout` | 故障转移超时 | 3分钟 |
3.3 启动哨兵
# 启动3个哨兵
docker run -d --name sentinel1 \
-p 26379:26379 \
-v /path/to/sentinel.conf:/usr/local/etc/redis/sentinel.conf \
redis:7.2-alpine \
redis-sentinel /usr/local/etc/redis/sentinel.conf
# 验证哨兵状态
redis-cli -h localhost -p 26379 INFO sentinel
# sentinel_masters:1
# sentinel_tilt:0
# sentinel_running_scripts:0
# master0:name=mymaster,status=ok,address=127.0.0.1:6379
3.4 Java客户端连接
// Jedis连接哨兵
public class RedisSentinelDemo {
public static void main(String[] args) {
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.1.101:26379");
sentinels.add("192.168.1.102:26379");
sentinels.add("192.168.1.103:26379");
JedisSentinelPool pool = new JedisSentinelPool(
"mymaster", // 主节点名称
sentinels,
new JedisPoolConfig(),
3000, // 连接超时
"master123" // 密码
);
// 自动获取当前Master
Jedis jedis = pool.getResource();
jedis.set("key", "value");
jedis.close();
}
}
# Spring Boot配置
spring:
redis:
sentinel:
master: mymaster
nodes: 192.168.1.101:26379,192.168.1.102:26379,192.168.1.103:26379
password: master123
四、Cluster模式配置
4.1 Cluster分片原理
▲ 图2:Redis Cluster分片架构
**分片策略**:
- 16384个槽位(slot)
- CRC16(key) % 16384 决定槽位
- 每个主节点负责一部分槽位
- 客户端直接连接对应节点
4.2 创建Cluster集群
# 准备6个Redis节点(3主3从)
for i in {1..6}; do
port=$((7000 + i - 1))
mkdir -p redis-node-${i}
cat > redis-node-${i}/redis.conf << EOF
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
requirepass cluster123
masterauth cluster123
EOF
docker run -d --name redis-node-${i} \
-p ${port}:${port} \
-v $(pwd)/redis-node-${i}:/data \
redis:7.2-alpine redis-server /data/redis.conf
done
4.3 初始化Cluster
# 使用redis-cli创建集群
redis-cli -a cluster123 --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 Cluster Check (using node 127.0.0.1:7000)
M: abc123... 127.0.0.1:7000
slots:0-5460 (5461 slots)
S: def456... 127.0.0.1:7003 replicates abc123...
M: ghi789... 127.0.0.1:7001
slots:5461-10922 (5462 slots)
S: jkl012... 127.0.0.1:7004 replicates ghi789...
M: mno345... 127.0.0.1:7002
slots:10923-16383 (5461 slots)
S: pqr678... 127.0.0.1:7005 replicates mno345...
4.4 集群操作
# 查看集群状态
redis-cli -a cluster123 -c -h 127.0.0.1 -p 7000 cluster info
# 查看节点列表
redis-cli -a cluster123 -c -h 127.0.0.1 -p 7000 cluster nodes
# 手动故障转移
redis-cli -a cluster123 -c -h 127.0.0.1 -p 7003 failover
# 重新分配槽位
redis-cli -a cluster123 --cluster reshard 127.0.0.1:7000 \
--cluster-to <new-node-id> \
--cluster-slots <number-of-slots> \
--cluster-yes
4.5 Java客户端
// Jedis Cluster
public class RedisClusterDemo {
public static void main(String[] args) {
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 cluster = new JedisCluster(
nodes,
3000, // 连接超时
3000, // 读取超时
3, // 重试次数
"cluster123",// 密码
new JedisPoolConfig()
);
// 自动路由到正确节点
cluster.set("key1", "value1");
cluster.set("key2", "value2");
cluster.close();
}
}
五、生产最佳实践
5.1 内存优化
# 内存限制
maxmemory 10gb
maxmemory-policy allkeys-lru
# 内存碎片整理
activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100
# 持久化策略
appendonly yes
appendfsync everysec
rdbcompression yes
rdbchecksum yes
5.2 安全配置
# 绑定IP
bind 10.0.0.0/8
# 认证
requirepass strong_password_here
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
# TLS加密
tls-port 6380
port 0
tls-cert-file /path/to/redis.crt
tls-key-file /path/to/redis.key
tls-ca-cert-file /path/to/ca.crt
5.3 监控告警
# Redis Exporter + Prometheus
docker run -d --name redis-exporter \
-p 9121:9121 \
-v /path/to/redis.conf:/redis.conf \
oliver006/redis_exporter \
--redis.addr=redis://127.0.0.1:6379 \
--redis.password=cluster123 \
--config-command-file=/redis.conf
**关键监控指标**:
- `redis_connected_clients`- 连接数
- `redis_memory_used_memory`- 内存使用
- `redis_replication_offset`- 复制延迟
- `redis_slave_reconnect_seconds`- 从节点重连
- `redis_cluster_slots_assigned`- 槽位分配
六、常见问题
Q1: 主从复制延迟?
# 查看复制状态
redis-cli -h master -p 6379 INFO replication
# 检查网络延迟
redis-cli -h slave -p 6380 --latency
# 优化
# 1. 使用物理机,避免虚拟化开销
# 2. 调整repl-diskless-sync yes(无盘同步)
# 3. 合理设置repl-backlog-size
Q2: 哨兵多次选举?
# 增加哨兵数量或调整quorum
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
Q3: Cluster槽位迁移?
# 在线迁移槽位(不停止服务)
redis-cli --cluster reshard 127.0.0.1:7000 \
--cluster-from <source-node-id> \
--cluster-to <target-node-id> \
--cluster-slots 1000 \
--cluster-yes
总结
模式 | 特点 | 适用规模 | 建议 |
**主从** | 简单、读写分离 | <10万QPS | 测试/开发环境 |
**哨兵** | 自动故障转移 | 10~50万QPS | 中小型生产 |
**Cluster** | 数据分片、水平扩展 | 50万+QPS | 大型生产环境 |
**架构建议**:
- **小型项目**:1主2从 + 3哨兵
- **中型项目**:1主2从 × 3组 + 3哨兵
- **大型项目**:Cluster模式,6节点起步
*数据不丢,服务不断,选对高可用方案。*
