一、前言:为什么 Redis Cluster 不需要哨兵?
在 Redis 哨兵(Sentinel)架构中,我们需要额外部署 Sentinel 节点来监控主从状态并执行故障转移。
但当你使用 Redis 分片集群(Cluster) 时,会发现:
✅ 无需 Sentinel!
✅ 主节点宕机后,从节点自动升主!
✅ 全程去中心化,无单点协调者!
这背后,是 Redis Cluster 内置的 自动故障转移(Automatic Failover)机制。
本文将带你深入其核心原理,揭秘:
- 故障如何被“集体”发现?
- 从节点如何“竞选”成为新主?
- 客户端如何“无感”切换?
- 如何确保不发生“脑裂”?
二、自动故障转移全景流程
整个过程完全由集群内部节点协作完成,分为 4 个关键阶段:

下面,我们逐层拆解。
三、阶段 1:故障检测 —— “主观下线”到“客观下线”
3.1 主观下线(PFAIL)
- 每个节点每秒向其他节点发送 PING 心跳
- 若某主节点 M 在 cluster-node-timeout(默认 15 秒)内未响应,则当前节点将其标记为 PFAIL(Possible Fail)
⚠️ PFAIL 是本地状态,不代表集群共识。
3.2 客观下线(FAIL)—— 达成集群共识
- 节点 A 发现 M 失联 → 在 gossip 消息中携带 “M is PFAIL”
- 当 超过半数主节点 都报告 M 为 PFAIL 时,A 将 M 标记为 FAIL
- A 向全集群广播 FAIL <M-node-id> 消息
🔑 关键规则:
- 只有主节点参与投票
- 需要 > N/2 主节点同意(N = 主节点总数)
- 例如:3 主集群 → 需 2 个主节点确认
✅ 设计意义:防止网络分区导致误判(如少数节点失联)。
四、阶段 2:从节点发起选举 —— “谁来接班”?
一旦主节点被标记为 FAIL,其所有从节点都会尝试升主。
4.1 选举资格校验
从节点需满足:
4.2 选举流程(类 Raft 协议)
- 若当前纪元未投票 → 回复 FAILOVER_AUTH_ACK
✅ 防脑裂:同一纪元只能投一票,确保唯一胜出者。
五、阶段 3:执行故障转移 —— 新主上任
当选从节点立即执行:
步骤 1️⃣:升为主节点
SLAVEOF NO ONE
- 停止复制
- 将自己负责的 slots 状态设为 serving
步骤 2️⃣:广播新身份
- 向全集群发送 PONG 消息,声明:“我是新主,接管 slots X-Y”
- 更新本地 nodes.conf 文件(持久化配置)
步骤 3️⃣:原主恢复后自动降级
- 原主重启后,通过 gossip 发现已有新主
- 自动执行 REPLICAOF <new-master-ip> <port>
- 变为从节点,同步新主数据
💡 优势:无需人工干预,原主自动回归从属角色。
六、阶段 4:客户端无感切换 —— 智能重定向
6.1 切换期间的行为
- 客户端访问原主 slot:
- 连接断开 → 报错 Connection refused
- 连接存活但主已下线 → 返回 -CLUSTERDOWN 或超时
6.2 自动重试与拓扑刷新
现代客户端(如 Lettuce、Jedis Cluster)会:
✅ 效果:应用可能短暂失败(如 500ms~2s),但重试后即可成功,实现“准无感”切换。
6.3 Spring Boot 最佳实践
// Lettuce 默认启用拓扑刷新
@Configuration
public class RedisConfig {
@Bean
public LettuceClientConfiguration lettuceClientConfiguration() {
return LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(2))
.clientOptions(ClusterClientOptions.builder()
.topologyRefreshOptions(
ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(30))
.enableAllAdaptiveRefreshTriggers()
.build())
.build())
.build();
}
}
七、实战验证:模拟主节点宕机
7.1 环境
- 集群:3 主(7001~7003)+ 3 从(7004~7006)
- 主 7001 负责 slots 0–5460
7.2 操作步骤
# 1. 写入数据
redis-cli -c -p 7001 SET user:1001 "Alice"
# 2. 杀死主节点
kill $(pgrep -f "7001")
# 3. 观察从节点(7004)日志
tail -f /var/log/redis/7004.log
# 日志应包含:
# 1:S … Failover auth granted.
# 1:M … Becoming a master.
# 4. 验证新主
redis-cli -p 7004 CLUSTER NODES | grep master
# 7004 应显示为 master,且负责 0-5460
# 5. 读写验证
redis-cli -c -p 7004 GET user:1001 # 返回 "Alice"
redis-cli -c -p 7004 SET user:1002 "Bob" # 写入成功
✅ 全程耗时约 15~30 秒(由 cluster-node-timeout 决定)
八、关键配置参数与调优建议
| cluster-node-timeout | 15000 ms | 故障判定超时 | 网络稳定设 10000;跨机房设 30000 |
| cluster-replica-validity-factor | 10 | 从节点最大 lag(× timeout) | 默认 150s,可适当调大 |
| cluster-require-full-coverage | yes | 是否允许部分 slot 不可用 | 必须设为 no!避免全集群不可用 |
📌 重要:cluster-require-full-coverage no
当某个分片故障时,其他分片仍可正常读写!
九、常见问题排查
❌ 问题 1:故障转移未触发
- 原因:主节点数 < 3,无法达成多数派
- 解决:生产环境至少部署 3 主 3 从
❌ 问题 2:多个从节点同时升主(脑裂)
- 原因:网络分区导致两个分区各自达成多数派
- 预防:确保网络可靠,避免跨机房部署时分区
❌ 问题 3:客户端长时间无法连接
- 原因:未启用拓扑自动刷新
- 解决:Lettuce 配置 enablePeriodicRefresh
十、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!


