一、前言:Redis Cluster 如何实现“无人值守”高可用?
在 Redis 分片集群(Cluster)中,每个分片(shard)都由一个主节点和至少一个从节点组成。
当某个主节点因宕机、网络隔离等原因不可用时,集群必须自动选出新主,否则该分片将完全不可写。
Redis Cluster 内置了去中心化的故障检测与转移机制,无需哨兵(Sentinel),即可实现秒级自动恢复。
本文将深入解析:
✅ 故障如何被发现?
✅ 从节点如何升主?
✅ 客户端如何感知切换?
✅ 整个过程是否真的“无感”?
二、故障转移全景流程
整个过程可分为 4 个阶段:

下面我们将逐一拆解每个阶段的内部机制。
三、阶段 1:故障检测 —— 谁说了算?
3.1 检测机制:基于 gossip + 心跳
- 每个节点每秒向其他节点发送 PING 消息
- 若某节点 P 在 cluster-node-timeout(默认 15 秒)内未响应,则标记为 PFAIL(主观下线)
3.2 达成共识:FAIL 状态广播
- 节点 A 发现主节点 M 失联 → 标记为 PFAIL
- A 在后续 gossip 消息中携带 “M is PFAIL”
- 当超过半数主节点都认为 M 失联时,A 将 M 标记为 FAIL(客观下线)
- A 向全集群广播 FAIL <M-node-id> 消息
🔑 关键点:
- 只有主节点参与投票(从节点不参与)
- 需要 > N/2 主节点同意(N = 主节点总数)
- 例如:3 主集群 → 需 2 个主节点确认
四、阶段 2:从节点发起选举
一旦主节点被标记为 FAIL,其从节点会尝试升主。
4.1 选举触发条件
- 从节点收到 FAIL 消息
- 自身与主节点失联时间 > repl-ping-replica-period(默认 10 秒)
- 从节点数据较新(复制偏移量接近主)
4.2 选举流程(类 Raft)
- 若未投票且纪元有效 → 回复 FAILOVER_AUTH_ACK
✅ 举例:3 主集群 → 需 2 票才能升主
五、阶段 3:执行故障转移
当选从节点执行以下操作:
步骤 1️⃣:升为主节点
- 执行 SLAVEOF NO ONE
- 将自己负责的 slots 状态从 importing 改为 serving
步骤 2️⃣:广播新拓扑
- 向全集群发送 PONG 消息,声明自己是新主
- 更新 nodes.conf 文件(持久化配置)
步骤 3️⃣:接管客户端请求
- 对原主节点的 slot 范围提供读写服务
步骤 4️⃣:原主恢复后自动变为从
- 原主重启后,发现集群已有新主
- 自动执行 REPLICAOF <new-master>,同步数据
六、阶段 4:客户端如何感知切换?
6.1 切换期间的行为
- 客户端访问原主节点的 slot:
- 若连接已断 → 报错 Connection refused
- 若连接存活但主已下线 → 返回 -CLUSTERDOWN 或超时
6.2 自动重定向(关键!)
现代 Redis 客户端(如 Lettuce、Jedis Cluster)会:
✅ 效果:应用层可能短暂报错(如 RedisCommandTimeoutException),但重试后即可成功,实现“准无感”切换。
6.3 Spring Boot 示例
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 即使主切换,opsForValue() 仍可工作(Lettuce 自动重连)
public String getValue(String key) {
try {
return (String) redisTemplate.opsForValue().get(key);
} catch (Exception e) {
// 可加简单重试逻辑
Thread.sleep(100);
return (String) redisTemplate.opsForValue().get(key);
}
}
七、实战验证:模拟主节点宕机
7.1 环境
- 3 主 3 从集群:7001~7006
- 主 7001 负责 slots 0–5460
7.2 操作步骤
# 1. 写入测试数据
redis-cli -c -p 7001 set test_key "before_failover"
# 2. 杀死主节点
kill $(pgrep -f "7001")
# 3. 观察从节点(7004)日志
tail -f /opt/redis-cluster/7004/redis.log
# 应看到:Failover auth granted, Becoming a master.
# 4. 查询新主
redis-cli -p 7004 cluster nodes | grep master
# 7004 应显示为 master,且负责 0-5460
# 5. 验证数据可读写
redis-cli -c -p 7004 get test_key # 返回 "before_failover"
redis-cli -c -p 7004 set new_key "after" # 写入成功
✅ 全程耗时约 15~30 秒(取决于 cluster-node-timeout)
八、关键配置参数
| cluster-node-timeout | 15000 ms | 节点超时判定时间 | 网络稳定可设 10000;跨机房设 30000 |
| cluster-replica-validity-factor | 10 | 从节点升主最大 lag(× timeout) | 默认 10×15s=150s,可适当调大 |
| cluster-require-full-coverage | yes | 是否允许部分 slot 不可用 | 生产建议设为 no,避免全集群不可用 |
💡 重要:cluster-require-full-coverage no
当某个分片不可用时,其他分片仍可正常读写!
九、常见问题排查
❌ 问题 1:故障转移未触发
- 原因:主节点数 < 3,无法达成多数派
- 解决:确保至少 3 个主节点
❌ 问题 2:从节点未升主
- 原因:从节点数据太旧(lag 过大)
- 检查:INFO REPLICATION 中 master_repl_offset
❌ 问题 3:客户端长时间无法连接
- 原因:客户端未启用集群拓扑刷新
- 解决:Lettuce 配置 refreshPeriod:
spring:
redis:
lettuce:
cluster:
refresh-period: 30s
十、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

