欢迎光临
我们一直在努力

Redis分片集群自动故障转移

一、前言:为什么 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 选举资格校验

从节点需满足:

  • 与主节点失联时间 > repl-ping-replica-period(默认 10 秒)
  • 自身数据较新(复制偏移量接近主)
  • cluster-replica-validity-factor 允许升主(默认 10 × timeout = 150 秒)
  • 4.2 选举流程(类 Raft 协议)

  • 从节点将自身 currentEpoch +1,作为选举纪元
  • 向所有主节点发送 FAILOVER_AUTH_REQUEST
  • 主节点收到请求:
    • 若当前纪元未投票 → 回复 FAILOVER_AUTH_ACK
  • 从节点获得 > N/2 主节点投票 → 当选新主
  • ✅ 防脑裂:同一纪元只能投一票,确保唯一胜出者。


    五、阶段 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)会:

  • 捕获异常
  • 主动查询任一存活节点:CLUSTER SLOTS
  • 更新本地 slot → node 映射表
  • 重试请求到新主
  • ✅ 效果:应用可能短暂失败(如 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

    十、结语

    感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

    赞(0)
    未经允许不得转载:171主机测评 » Redis分片集群自动故障转移
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址