哨兵选举
00:00
Redis Sentinel 哨兵选举机制:主观下线、客观下线、Leader 选举与 Raft 算法、故障转移流程。
1. Sentinel 架构
1.1 Sentinel 集群
┌──────────┐ ┌──────────┐ ┌──────────┐
│Sentinel 1│ │Sentinel 2│ │Sentinel 3│
└─────┬────┘ └─────┬────┘ └─────┬────┘
│ │ │
└─────────────┼─────────────┘
│ 监控
┌─────────────┼─────────────┐
↓ ↓ ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Master │ │ Replica1 │ │ Replica2 │
└──────────┘ └──────────┘ └──────────┘
1.2 Sentinel 职责
- 监控:持续检测主从库是否正常
- 通知:故障时通知管理员或应用
- 自动故障转移:主库故障时自动切换
- 配置提供者:告知客户端当前主库地址
2. 下线检测
2.1 主观下线(SDOWN)
单个 Sentinel 认为节点不可用:
Sentinel 每秒向节点发送 PING
超过 down-after-milliseconds 无有效回复 → 标记为 SDOWN
# 配置
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
2.2 客观下线(ODOWN)
多个 Sentinel 都认为主库不可用:
1. Sentinel A 检测到 Master SDOWN
2. Sentinel A 向其他 Sentinel 发送 SENTINEL is-master-down-by-addr
3. 超过 quorum 个 Sentinel 确认 SDOWN → 标记为 ODOWN
4. ODOWN 触发故障转移
quorum:配置中 sentinel monitor 的最后一个参数,表示需要多少个 Sentinel 同意才能判定客观下线。
3. Leader 选举(Raft 算法)
3.1 为什么需要 Leader
只有被选为 Leader 的 Sentinel 才能执行故障转移,避免多个 Sentinel 同时执行。
3.2 Raft 选举流程
1. Sentinel 确认 Master ODOWN
2. Sentinel 自增 current_epoch(任期号)
3. 向其他 Sentinel 请求投票(SENTINEL is-master-down-by-addr)
4. 其他 Sentinel 每个任期只投一票(先到先得)
5. 获得多数票(> N/2)的 Sentinel 成为 Leader
6. Leader 执行故障转移
3.3 选举规则
规则1: 先到先得(FIFO)— 每个 epoch 只投一票
规则2: 获得多数票 — > ceil(N/2),N 为 Sentinel 总数
规则3: epoch 递增 — 新选举的 epoch 必须大于当前值
选举示例(3个 Sentinel):
Sentinel A: epoch=1, 请求投票 → 获得 A(自投), B → 2票 > 1.5 → 成为 Leader
Sentinel B: epoch=1, 请求投票 → 已投给A → 拒绝
Sentinel C: epoch=1, 请求投票 → 已投给A → 拒绝
3.4 选举超时与重试
如果未获得多数票:
等待随机时间(避免同时发起选举)
自增 epoch
重新请求投票
最大重试次数: 无限制
超时时间: 故障转移超时(failover-timeout)
4. 故障转移
4.1 从库选择规则
Leader Sentinel 按以下规则选择新主库:
1. 排除下线或断线的从库
2. 排除最近5秒内未回复 INFO 的从库
3. 排除与旧主库断开时间过长的从库
(down-after-milliseconds * 10)
4. 按优先级选择(replica-priority 越小越优先)
5. 优先级相同,选择复制偏移量最大的(数据最新)
6. 偏移量相同,选择 runid 最小的
4.2 故障转移步骤
步骤1: 选出新主库
Leader Sentinel 根据上述规则选出最优从库
步骤2: 升级新主库
SENTINEL SLAVEOF NO ONE → 新主库停止复制
步骤3: 修改其他从库的复制目标
其他从库执行 SLAVEOF new_master
步骤4: 更新 Sentinel 配置
所有 Sentinel 更新 Master 地址
步骤5: 通知客户端
客户端通过 Sentinel 获取新 Master 地址
4.3 故障转移时间线
T+0s: Master 下线
T+30s: Sentinel 检测到 SDOWN(down-after-milliseconds=30s)
T+31s: 确认 ODOWN,发起 Leader 选举
T+32s: Leader 选举完成
T+33s: 选出新主库,执行 SLAVEOF NO ONE
T+35s: 其他从库开始复制新主库
T+40s: 故障转移完成
5. Sentinel 配置最佳实践
5.1 推荐配置
# 至少3个 Sentinel(保证多数票)
sentinel monitor mymaster 127.0.0.1 6379 2
# down-after-milliseconds: 根据网络延迟调整
sentinel down-after-milliseconds mymaster 10000
# failover-timeout: 故障转移超时
sentinel failover-timeout mymaster 60000
# parallel-syncs: 故障转移后同时向新主库发起复制的从库数
sentinel parallel-syncs mymaster 1
5.2 quorum 设置
quorum 建议值: ceil(N/2),N 为 Sentinel 数量
3个 Sentinel: quorum=2
5个 Sentinel: quorum=3
quorum 过低: 可能误判(网络分区时)
quorum 过高: 可能无法触发故障转移
5.3 客户端连接
# Python 客户端通过 Sentinel 获取 Master
from redis.sentinel import Sentinel
sentinel = Sentinel([
('sentinel1', 26379),
('sentinel2', 26379),
('sentinel3', 26379)
], socket_timeout=0.1)
master = sentinel.master_for('mymaster', password='xxx')
slave = sentinel.slave_for('mymester', password='xxx')