从零起步学习Redis || 第十一章:主从切换时的哨兵机制如何实现及项目实战

前言:

在之前的文章中,我们已经讲过了redis的主从架构,那么此时就出现了这样一个问题:如果Redis的一个主节点突然断连/宕机了,整个redis集群的写操作就会失效,为了解决这一问题,就有了我们今天所要学习的内容:哨兵(Sentinel)机制

一、为什么要有哨兵机制?

在 Redis 主从复制(Master-Slave)架构中,主节点(Master)负责写操作,从节点(Slave)负责读操作。

问题是:

一旦主节点宕机,整个集群的写操作就会失效。

如果没有哨兵机制,就得使用人工切换主从节点,这样高可用性就低了

为了解决主节点故障时的高可用问题,Redis 引入了 哨兵(Sentinel)机制,它可以:

  • 自动监控主从节点的运行状态;

  • 在主节点故障时,自动完成主从切换(Failover)

  • 保证系统的高可用性。

总结一句话:

哨兵机制的目的是让 Redis 集群在主节点故障时自动恢复服务,不需要人工干预。


二、哨兵机制是如何工作的?

哨兵(Sentinel)本质上是一个特殊的 Redis 进程,它主要负责三件事:监控(Monitor)选主(Elect)通知(Notify)

1. 监控

每个哨兵定期向主从节点发送 PING 命令,判断它们是否在线。

  • 如果节点一段时间没有响应,哨兵会认为它"可能下线"(主观下线,Subjectively Down)。

  • 如果多个哨兵都同意该节点下线,则认为它"客观下线"(客观下线,Objectively Down)。

2. 选主

当主节点被判定为客观下线后,哨兵集群会进行选举,选出一个哨兵来执行主从切换的操作。

3. 通知

哨兵会将新的主节点信息通知给所有 Redis 客户端和其他从节点,更新它们的主从关系。


三、如何判断主节点真的故障了?

图中提到了两种判断:

1. 主观下线(Subjectively Down)

某个哨兵单独认为主节点失联了(比如 ping 超时未响应)。

但这只是一个"怀疑",不代表主节点真的挂了。

实现:

哨兵每隔一段时间后会发送ping命令给主从节点,如果主从节点没有在规定的时间内响应,就会判断为主观下线。

2. 客观下线(Objectively Down)

当多个哨兵都报告主节点下线后,通过投票达成共识,认为主节点确实宕机,进入故障转移流程。

实现:

当有1个哨兵判断1个节点为主观下线后,它会向其他哨兵节点发出命令,此时其他哨兵根据自身和目标节点的连接状态来判断是否赞成或反对,当赞成票数数量达到quorum值(大于等于)(哨兵配置文件)时,就会判定节点为客观下线。

注意:quorum一般设置为(哨兵节点数量*1/2+1)


四、由哪个哨兵执行主从故障转移?

不是所有哨兵都会去做主从切换。

会通过 哨兵选举机制(Raft-like Leader 选举)

选出一个"哨兵领导者"(Sentinel Leader)来执行故障转移。

选举过程使用 Redis 内置的投票机制

  • 每个哨兵给一个候选者投票;

  • 获得半数以上票数的哨兵成为领导者;

  • 领导者负责后续主从切换。

问题1:谁是候选者?

答:哪个哨兵节点判断主节点客观下线,哪个节点就是候选者,候选者就是想成为leader的哨兵节点。

问题2:候选者如何成为leader?

答:


问题3:既然候选者都会先把票投给自己,那么非候选者投完票后是否会出现持有最高票数的候选者票数没能达到半数以上导致无法主从切换?

答:

那么,Redis 哨兵的处理方式是:

本轮选举作废,等待下一轮重新选举。

哨兵如何重新发起选举?

  • 每个哨兵会在一个称为 epoch 的时间周期内记录自己是否已投票。

  • 如果在一定时间内没选出 Leader(比如几秒钟),

    就会自动进入下一轮选举(epoch + 1),并重新随机等待一小段时间再发起选举。

因为每轮都有随机延迟,所以随着重试次数增加:

  • 某个哨兵更可能比别人稍早发起选举;

  • 其他哨兵还没开始投票时,就会收到它的请求;

  • 从而给它投票;

  • 最终选出一个获得多数票的 Leader。

Redis 哨兵利用两个机制来保证"最终一定能选出领导者":

  1. 随机超时机制

    每个哨兵在发起选举前等待一个随机时间(例如 100ms ~ 500ms),

    避免所有哨兵同时发起选举造成分票。

  2. epoch 轮次机制

    每次选举失败会自动增加 epoch 值,

    哨兵在下一轮重新发起选举,直到有人获得半数票。

换句话说:

Redis Sentinel 可能在某一时刻"暂时无法选出 Leader",

但不会永久卡死,最终一定能选出一个。

五、主从故障转移的过程是怎样的?

当选出的哨兵 Leader 执行故障转移时,主要分为以下步骤:

  1. 选出新的主节点

    从剩余的从节点中,选择一个最合适的节点作为新的主节点。

    (优先选择延迟最小、数据最完整的从节点)

  2. 将新主节点提升为主节点

    执行命令:

    复制代码
    SLAVEOF NO ONE
  3. 通知其他从节点

    让它们从新主节点同步数据。

    复制代码
    SLAVEOF <new-master-ip> <port>
  4. 通知客户端更新连接

    客户端通过哨兵的监控发现主节点已变更,自动连接新主节点。

问题1:新节点如何选出?

答:

Redis+有个叫+down-after-milliseconds+*+10+配置项,其+down-after-milliseconds+是主从节点断连的最大连接超时时间。如果在down-after-milliseconds中主从节点的网络连接不上,我们就认为其断连了,断连次数超过10次,就说明其网络状态不好,不适合作为新节点。

接下来就是三轮考察:

第一轮:优先级

第二轮:(数据的)复制进度

第三轮:节点的ID

问题2:节点切换后,新的主节点和客户端如何连接?

答:


六、哨兵集群是如何组成的?

在生产环境中,我们通常部署 多个哨兵实例(至少 3 个) 形成哨兵集群。

它们通过 发布/订阅(Pub/Sub)机制 互相通信,

共享主从节点的状态信息,实现一致判断和选举。

结构举例:

复制代码
+------------------+
|   Sentinel 1     |
|   Sentinel 2     |  <===> 互相通信
|   Sentinel 3     |
+------------------+

        |
        v
+------------------------+
|   Master  <----> Slaves|
+------------------------+

七、Java 开发者角度:客户端如何使用哨兵?

在 Java 项目中,可以使用 Jedis 或 Lettuce 客户端 连接 Redis 哨兵集群。

例如使用 Jedis:

复制代码
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);

try (Jedis jedis = pool.getResource()) {
    jedis.set("name", "Redis Sentinel");
    System.out.println(jedis.get("name"));
}

"mymaster" 是哨兵配置中定义的主节点名称。

客户端会自动识别主节点变化,保持连接稳定。


总结

模块 功能 说明
监控 检测主从节点健康状态 PING 检查
选主 确定新主节点 投票选举哨兵 Leader
通知 更新客户端与从节点的主节点信息 Pub/Sub 发布新主节点信息
故障转移 自动主从切换 提升从节点为主节点
高可用 防止服务中断 集群自动恢复
相关推荐
间彧6 小时前
AspectJ详解与项目实战指南
后端
爱读源码的大都督6 小时前
RAG效果不理想?试试用魔法打败魔法:让大模型深度参与优化的三阶段实战
java·人工智能·后端
间彧6 小时前
Spring Boot @Lazy注解详解与实战应用
后端
间彧6 小时前
SpEL表达式详解与应用实战
后端
埃泽漫笔6 小时前
mq的常见问题
java·mq
源码部署26 小时前
【大厂学院】微服务框架核心源码深度解析
后端
倔强的石头_7 小时前
面向大数据架构的演进:为何 Apache IoTDB 是与生态无缝融合的理想之选?
数据库
间彧7 小时前
微服务架构中Spring AOP的最佳实践与常见陷阱
后端
间彧7 小时前
Spring AOP详解与实战应用
后端