哨兵选举
Redis Sentinel 哨兵选举机制:主观下线、客观下线、Leader 选举与 Raft 算法、故障转移流程。
1. Sentinel 架构
1.1 Sentinel 集群
flowchart TD
S1[Sentinel 1] --> M[Master]
S2[Sentinel 2] --> M
S3[Sentinel 3] --> M
M --> R1[Replica1]
M --> R2[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)
准确地说,Sentinel 的 Leader 选举借鉴了 Raft 的「任期 + 多数票」思想, 但并不是标准 Raft 实现(无日志复制语义)。官方文档只称其为 leader election。
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: 升级新主库
向选中的从库发送 SLAVEOF NO ONE(新版语法 REPLICAOF NO ONE),
停止复制并升为角色 master
步骤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('mymaster', password='xxx')
注意区分两个多数:客观下线(ODOWN)只要求 quorum 个 Sentinel 确认, 而执行故障转移的 Leader 选举必须获得全体 Sentinel 的多数票(> N/2)。 quorum 可以小于多数(如 3 个 Sentinel 配 quorum=2),此时判定下线更快, 但 Leader 选举仍需多数 Sentinel 在线,否则故障转移不会发生。 另外,SDOWN/ODOWN 只针对主库;从库与 Sentinel 自身的故障只有 SDOWN 状态。
哨兵配置
基本写法:sentinel.conf 配置
sentinel monitor <主库别名> <host> <port> <quorum>
# sentinel.conf 配置文件
port 26379
sentinel monitor mymaster 192.168.1.10 6379 2
sentinel auth-pass mymaster <主库密码>
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# quorum=2:2 个哨兵同意才判定主观下线转客观下线
# down-after-milliseconds:30s 无响应判定下线
# parallel-syncs:故障转移时并行同步的从库数
# failover-timeout:故障转移超时
基本写法:启动哨兵
redis-sentinel <配置文件> | redis-server <配置文件> --sentinel
# 方式一:redis-sentinel 专用命令
redis-sentinel /etc/redis/sentinel.conf
# 方式二:redis-server 加 --sentinel 参数
redis-server /etc/redis/sentinel.conf --sentinel
# 集群部署:至少 3 个哨兵节点,分散部署
哨兵查询命令
基本写法:SENTINEL masters
SENTINEL masters | SENTINEL master <主库别名>
-- 查看所有被监控的主库
SENTINEL masters
-- 查看指定主库详情
SENTINEL master mymaster
-- 返回:name, ip, port, runid, role-reported, slaves, sentinels,
-- quorum, flags(master), down-after-milliseconds, etc.
基本写法:查看从库与哨兵
SENTINEL slaves <主库别名> | SENTINEL sentinels <主库别名>
-- 查看主库下的从库列表
SENTINEL slaves mymaster
-- 查看监控同一主库的其他哨兵
SENTINEL sentinels mymaster
基本写法:获取主库地址
SENTINEL get-master-addr-by-name <主库别名>
-- 客户端连接哨兵查询当前主库地址
SENTINEL get-master-addr-by-name mymaster
-- 返回:1) "192.168.1.11" 2) "6379"(故障转移后地址会变)
故障转移
基本写法:手动故障转移
SENTINEL failover <主库别名>
-- 手动触发故障转移,将从库提升为主库
SENTINEL failover mymaster
-- 故障转移流程:
-- 1. 哨兵标记主库下线
-- 2. 选举领头哨兵
-- 3. 选择最优从库(优先级>偏移量>runid)
-- 4. 从库执行 SLAVEOF NO ONE 升主
-- 5. 其他从库指向新主库
-- 6. 旧主恢复后变为从库
基本写法:强制重置
SENTINEL reset <pattern>
-- 重置匹配 pattern 的主库监控(清空状态重新发现)
SENTINEL reset my*
-- 重置所有
SENTINEL reset *
-- 重置后哨兵会重新发现主从拓扑
基本写法:检查仲裁
SENTINEL ckquorum <主库别名>
-- 检查当前哨兵数是否足够达成仲裁
SENTINEL ckquorum mymaster
-- 返回 OK 表示可用;返回 error 表示哨兵不足
故障转移原理
基本写法:下线判定与选举
<主观下线> -> <客观下线> -> <_leader 选举> -> <选从升主>
-- 1. 主观下线(SDOWN):单个哨兵判定 down
-- 条件:down-after-milliseconds 内无响应
-- 2. 客观下线(ODOWN):quorum 个哨兵同意
-- 通过 SENTINEL is-master-down-by-addr 投票
-- 3. Leader 选举:Raft 协议选领头哨兵执行转移
-- 4. 从库选举优先级:
-- a. replica-priority 值小的优先(0 永不升主)
-- b. 复制偏移量大的优先(数据更新)
-- c. runid 字典序小的优先
客户端连接哨兵
基本写法:客户端订阅切换事件
SUBSCRIBE +switch-master | +sdown
-- 客户端订阅哨兵频道感知主库切换
SUBSCRIBE +switch-master
-- 故障转移后收到:mymaster 192.168.1.10 6379 192.168.1.11 6379
-- 订阅下线事件
PSUBSCRIBE *
-- 常见事件频道:
-- +switch-master:主库切换
-- +sdown:主观下线
-- +odown:客观下线
-- +failover-state-*:故障转移各阶段
-- +slave-reconf-sent:从库重配置
哨兵运维
基本写法:动态修改配置
SENTINEL set <主库别名> <参数> <值>
-- 动态修改哨兵配置(运行时生效)
SENTINEL set mymaster down-after-milliseconds 5000
SENTINEL set mymaster parallel-syncs 3
SENTINEL set mymaster failover-timeout 300000
SENTINEL set mymaster quorum 3
-- 动态添加监控主库
SENTINEL monitor newmaster 192.168.2.10 6379 2
-- 移除监控
SENTINEL remove newmaster
基本写法:flushconfig 持久化
SENTINEL flushconfig
-- 将当前哨兵状态写入配置文件(持久化)
SENTINEL flushconfig
-- 哨兵状态变更(发现新从库/哨兵)后建议执行