引言

在 Redis 主从架构中,哨兵(Sentinel)承担着故障检测与自动切换的关键职责。然而,多个哨兵节点如何协同工作?它们之间又是如何发现彼此、达成共识的?

本文将从哨兵利用 __sentinel__:hello 频道实现互相感知的机制入手,逐步拆解哨兵集群的完整工作流程,包括:

  • 哨兵之间如何发现彼此
  • 主观下线和客观下线是怎么判断的
  • Leader 哨兵如何选举产生
  • 新主库是如何被选出来的
  • 切换完成后,其他节点和客户端如何被通知

把这条链路看懂之后,Redis Sentinel 为什么能在不依赖外部组件的情况下实现高可用,就会清楚很多。

哨兵之间如何感知彼此

在 Redis 主从集群中,主库上有一个名为 __sentinel__:hello 的频道,不同哨兵就是通过这个频道相互发现、交换信息的。

可以这样理解:

  1. 每个哨兵都会定期把自己的信息发布到这个频道
  2. 其他哨兵会订阅这个频道
  3. 订阅方收到消息后,就知道当前还有哪些哨兵在共同监控这组主从实例

例如:

  • 哨兵 1 把自己的 IP 和端口发布到 __sentinel__:hello
  • 哨兵 2 和哨兵 3 订阅了该频道
  • 哨兵 2 和哨兵 3 收到后,就能感知到哨兵 1 的存在

所以哨兵集群的互相发现,并不是靠额外注册中心完成的,而是 Redis 自身提供的发布订阅机制完成的。

哨兵机制的基本流程

Redis 哨兵机制大致可以拆成四个阶段:

  1. 监控
  2. 故障判断
  3. Leader 选举
  4. 主从切换与通知

监控过程

哨兵会周期性地给所有主库、从库以及其他哨兵发送 PING 命令,用于检测节点是否存活。

从库故障判断

如果某个从库在规定时间内没有响应,哨兵会把它标记为下线节点。

这个超时时间通常由 down-after-milliseconds 控制,默认常见配置是 30 秒。

主库故障判断

主库的判断会更谨慎。

如果某个哨兵发现主库在 down-after-milliseconds 时间内没有响应,它会先把主库标记为:

  • 主观下线(Subjectively Down,简称 sdown

这里之所以只是“主观下线”,是因为:

  • 有可能是这个哨兵自己网络有问题
  • 也有可能只是它和主库之间链路异常

所以仅凭单个哨兵的判断,不能直接认定主库真的挂了。

什么是客观下线

如果一个哨兵判断主库主观下线,它会向其他哨兵发起询问:

  • 你们是否也认为这个主库不可用了

当足够多的哨兵都认为该主库不可用时,主库才会被标记为:

  • 客观下线(Objectively Down,简称 odown

这个判断通常要求达到配置的法定票数,也就是常说的 quorum。很多资料会简单理解为“半数以上同意”,但更准确地说,是:

  • 需要达到 Sentinel 配置中的法定票数要求

只有当主库被判定为客观下线后,后续的故障转移流程才会真正开始。

为什么要区分主观下线和客观下线

主观下线和客观下线的区别,本质上是在解决“误判”问题。

如果没有这层设计,那么:

  • 某一个哨兵自己网络波动
  • 它误以为主库挂了
  • 然后立刻触发切换

系统就会发生错误的主从切换。

所以 Redis Sentinel 的设计是:

  1. 单个哨兵只能做主观判断
  2. 多个哨兵形成共识后,才进入客观下线和故障转移

Leader 哨兵是怎么选出来的

当主库被判定为客观下线后,哨兵集群需要选出一个 Leader 哨兵来负责执行故障转移。

注意,这里选举的是:

  • 负责本次故障转移的 Leader 哨兵

而不是说“某个哨兵节点本身下线了,再选新的哨兵 leader”。

选举的基本思路

每个符合条件的哨兵都可以发起投票,请求其他哨兵把票投给自己。

整个过程本质上是:

  • 哨兵之间相互投票
  • 谁先拿到足够多的票,谁就成为本轮故障转移的 Leader

通常可以简单理解为:

  • 当某一个哨兵获得超过半数支持时,就可以成为 Leader

哨兵投票过程怎么理解

当主库被判定为客观下线后,各个哨兵会进入 Leader 选举阶段。

此时:

  1. 每个哨兵都可能发起一次“把票投给我”的请求
  2. 每个哨兵在一轮选举中通常只会投一票
  3. 谁先获得足够多的票,谁就负责本轮主从切换

所以这里真正被判定客观下线的是:

  • 主库

真正被选举出来的是:

  • 负责执行故障转移的 Leader 哨兵

这两个角色不能混在一起。

新主库是怎么选出来的

Leader 哨兵被选出来后,不会随便找一个从库升为主库,而是要按照规则进行筛选和打分。

这个过程通常可以概括为:

  • 先筛选
  • 再打分

筛选过程

首先要排除明显不合适的从库。

例如:

  • 与主库断连时间太长
  • 自身状态异常
  • 网络状况差

常见判断会参考 down-after-milliseconds * 10 这类阈值。如果某个从库和主库长时间失联,说明它的数据可能不够新,也可能网络状况不稳定,那么它就不适合作为新主库候选者。

打分过程

完成筛选后,Leader 哨兵会对剩余从库进行多轮比较。

第一轮:优先级高的从库优先

Redis 可以通过 replica-priority(老版本也常写作 slave-priority)配置从库优先级。

一般来说:

  • 优先级数值越小,优先级越高

优先级更高的从库,会更优先被考虑提升为主库。

第二轮:复制进度更接近旧主库的从库优先

主从复制过程中:

  • 主库会记录自己的复制偏移量
  • 从库也会记录自身同步到哪里

如果某个从库的复制进度最接近旧主库,说明它的数据通常更完整、更接近最新状态,因此得分更高。

第三轮:运行 ID 更小的从库优先

如果前面几个维度都相同,那么 Redis 会继续比较实例运行 ID 等信息,作为最终决策依据之一。

所以整个选主过程并不是随机的,而是带有明确规则的优先级选择。

主从切换完成后会发生什么

当 Leader 哨兵选定新的主库后,会继续完成后续通知和重配置工作。

主要包括:

通知其他从库

Leader 哨兵会把新主库的信息通知给其他从库,让它们执行:

  • replicaof

从而改为复制新的主库。

通知客户端

哨兵还会把新的主库连接信息通知给客户端,或者让客户端在下一次获取主库地址时拿到最新结果。

这样客户端后续写请求就会落到新的主库上。

恢复集群复制关系

在完成主从切换后,整个集群会逐步进入新的稳定状态:

  • 新主库开始接受写请求
  • 其他从库重新挂到新主库下
  • 原主库如果恢复,也会被重新配置为从库

Redis 哨兵集群如何选举

很多人会单独问一句:“Redis 哨兵集群到底是怎么选举的?”

如果把整个过程压缩一下,可以这样理解:

  1. 某个主库先被多个哨兵共同认定为客观下线
  2. 各个哨兵开始发起 Leader 选举
  3. 每个哨兵在本轮投票中通常只有一票
  4. 获得足够多选票的哨兵成为 Leader
  5. Leader 哨兵负责挑选新主库并完成故障转移

所以选举的目标不是选“长期总负责人”,而是:

  • 选出这一次故障转移的执行者

哨兵机制为什么能实现高可用

Redis Sentinel 能实现高可用,核心原因就在于它把几个关键能力组合在了一起:

  1. 哨兵之间能自动发现彼此
  2. 主库故障要通过多个哨兵共同确认
  3. 故障转移由选举出的 Leader 统一执行
  4. 新主库的选择不是随机,而是基于规则筛选
  5. 切换完成后,还能自动通知从库和客户端

也正因为有这套完整链路,Redis 在传统主从模式之上,才能进一步具备自动故障恢复能力。

总结

这篇文章可以压缩成几条核心结论:

  1. 哨兵之间通过主库上的 __sentinel__:hello 频道互相发现
  2. 单个哨兵只能判断主观下线,多个哨兵达成共识后才会形成客观下线
  3. 主库被判定客观下线后,哨兵集群会选出一个 Leader 负责故障转移
  4. 新主库的选择遵循“筛选 + 打分”的规则,而不是随机挑选
  5. 切换完成后,哨兵还会通知其他从库和客户端更新连接关系

如果把这些流程串起来理解,Redis 哨兵机制的核心逻辑其实非常清晰:

“先感知、再判断、后选举、再切换、最后通知。”


如果这篇文章对你有帮助,欢迎继续阅读本系列后续内容。若文中有不准确或需要补充的地方,也欢迎指出。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐