哨兵领导者选举
为什么需要选举领导者
在 Redis 哨兵架构中,当主节点被判定为”客观下线”后,需要有一个哨兵来负责执行故障转移操作。但如果有多个哨兵同时进行操作,可能会导致混乱。因此,哨兵集群需要先选举出一个”领导者”,由它统一指挥故障转移。
基于 Raft 算法的选举机制
Redis 哨兵的领导者选举借鉴了 Raft 共识算法的核心思想,但做了简化适配。选举过程如下:
1. 发起竞选
当一个哨兵确认主节点进入 ODOWN 状态后,它会先给自己投一票,然后向其他哨兵发送 SENTINEL is-master-down-by-addr 命令,附带当前的纪元(epoch)和它的运行 ID,请求其他哨兵投票给它。
每个哨兵有一个纪元计数器(current_epoch),每次发生主节点状态变化或发起选举时,纪元都会递增。这类似于 Raft 中的 term(任期)。每个纪元内最多只能进行一次成功的选举。
2. 投票规则
其他哨兵收到投票请求后,根据以下规则决定是否投票:
- 同一个纪元只能投一次票:每个哨兵在每个纪元中只能投出一张赞成票,遵循”先到先得”原则
- 只投票给第一个请求者:如果哨兵在本纪元还没有投过票,它会投票给第一个向它请求投票的哨兵
- 必须同意 ODOWN 判定:哨兵只有在自己也认为主节点处于 ODOWN 状态时,才会投票
3. 选举条件
要成为领导者,候选哨兵需要获得超过半数的选票:
所需票数 = (哨兵总数 / 2) + 1
例如,3 个哨兵需要 2 票,5 个哨兵需要 3 票。这个条件保证了在任意一次选举中,最多只能有一个哨兵获得足够的票数。
4. 超时重选
如果没有哨兵在故障转移超时时间内获得足够票数(例如由于网络分区导致投票分散),本次选举失败。哨兵会递增纪元号并重新发起选举。
为什么哨兵数量最好是奇数
由于需要”超过半数”的投票才能当选,哨兵集群的节点数最好是奇数:
| 总哨兵数 | 所需票数 | 容错数 |
|---|---|---|
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
可以看出,4 个哨兵和 3 个哨兵的容错能力一样(都只能容忍 1 个宕机),但奇数可以避免不必要的集群规模浪费。
与 Raft 算法的区别
Redis 哨兵的选举和标准 Raft 有几个关键差异:
- 没有日志复制:哨兵选举不需要复制日志,只负责选举执行人
- 简化的任期机制:纪元(epoch)只用于防止同一时段多次选举
- 无心跳维持:哨兵之间通过常规的 PING 通信,而不是专门的心跳机制
- 非强一致性:哨兵的共识目标是”就谁执行故障转移达成一致”,而不是维护一个状态机
面试要点
- 哨兵选举使用Raft 思想但不是完整 Raft 实现
- 需要超过半数(N/2+1) 的选票才能当选
- 每个纪元只能投一票,先到先得
- 奇数个哨兵更合理(容错能力与偶数相同但成本更低)
- 选举超时会递增纪元并重新选举
总结
哨兵领导者选举机制确保了在分布式环境下,故障转移操作由唯一一个哨兵协调执行,避免了多个哨兵同时操作导致的数据不一致问题。这是 Redis 高可用架构中关键的分布式共识环节。


暂无评论内容