哨兵(sentinel)
哨兵:执行守卫任务的士兵或看守人,在redis的哨兵模式中就是扮演监督/监控角色的节点。
架构组成
bash
┌─────────────────────────────────────────────────────────────┐
│ 哨兵集群(Sentinel Cluster) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Sentinel│◄──►│ Sentinel│◄──►│ Sentinel│ │
│ │ S1 │ │ S2 │ │ S3 │ │
│ │ :26379 │ │ :26380 │ │ :26381 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ 监控 + 故障转移决策 │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ ▼ │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Master │◄─────────│ Slave │ │ 主从复制(数据层) │
│ │ │ :6379 │ 同步 │ :6380 │ │ │
│ │ │ (写+读) │ │ (读) │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
推荐配置:至少 3 个 Sentinel 节点(奇数个,便于投票决策)
核心工作机制
监控机制
Sentinel 每秒向所有节点发送 PING 命令:
┌─────────────────────────────────────────────┐
│ Sentinel ──PING──► Master │
│ Sentinel ──PING──► Slave │
│ Sentinel ──PING──► 其他 Sentinel │
└─────────────────────────────────────────────┘
超时判定:
┌─────────────────────────────────────────────┐
│ down-after-milliseconds(默认 30s) │
│ │
│ 若 PING 在指定时间内无有效回复: │
│ • 主观下线(SDOWN, Subjective Down) │
│ → 单个 Sentinel 认为节点不可用 │
│ │
│ 若多数 Sentinel(quorum)都认为主观下线: │
│ • 客观下线(ODOWN, Objective Down) │
│ → 触发故障转移流程 │
└─────────────────────────────────────────────┘
故障转移流程
步骤 1:判定客观下线(ODOWN)
┌─────────────────────────────────────────────┐
│ Sentinel S1 发现 Master 主观下线
│ S1 向其他 Sentinel 询问 Master 状态
│ 若 ≥ quorum(法定人数) 个 Sentinel 同意 → ODOWN
└─────────────────────────────────────────────┘
↓
步骤 2:选举领头 Sentinel(Leader Election)
┌─────────────────────────────────────────────┐
│ 每个 Sentinel 向其他 Sentinel 发送请求:
│ "我要当 Leader,请投票给我"
│
│ 规则:
│ • 每个 Sentinel 只能投一票
│ • 先到先得
│ • 获得多数票的 Sentinel 成为 Leader
│
│ 目的:避免多个 Sentinel 同时执行故障转移
└─────────────────────────────────────────────┘
↓
步骤 3:选择新 Master
┌─────────────────────────────────────────────┐
│ Leader Sentinel 从 Slave 中选择新 Master:
│
│ 筛选条件(依次判断):
│ 1. 排除已下线的 Slave
│ 2. 排除最近 5 秒内没有回复 PING 的 Slave
│ 3. 排除与旧 Master 断开复制时间过长的 Slave
│ (防止数据太旧)
│ 4. 优先选择优先级高的(replica-priority)
│ 5. 优先选择复制偏移量大的(数据最新)
│ 6. 优先选择 Run ID 小的
└─────────────────────────────────────────────┘
↓
步骤 4:晋升与通知
┌─────────────────────────────────────────────┐
│ 1. 向选中的 Slave 发送 SLAVEOF NO ONE │
│ → 该 Slave 变为 Master │
│ │
│ 2. 向其他 Slave 发送 SLAVEOF new_master_ip │
│ → 重新建立主从复制 │
│ │
│ 3. 更新自身配置,记录新 Master 信息 │
│ │
│ 4. 向客户端发布 +switch-master 频道消息 │
│ → 通知客户端切换连接 │
└─────────────────────────────────────────────┘
核心配置参数
| 参数 | 默认值 | 说明 |
|---|---|---|
sentinel monitor mymaster 127.0.0.1 6379 2 |
--- | 监控的 Master 名、IP、端口、quorum(判定 ODOWN 的最小 Sentinel 数) |
sentinel down-after-milliseconds mymaster 30000 |
30000 | 主观下线判定时间(毫秒) |
sentinel parallel-syncs mymaster 1 |
1 | 故障转移时同时同步的 Slave 数量 |
sentinel failover-timeout mymaster 180000 |
180000 | 故障转移超时时间(毫秒) |
sentinel auth-pass mymaster password |
--- | Master 密码认证 |
客户端连接机制
传统方式(直连):
客户端 ──► Master ──► 读写
Master 宕机 → 客户端报错 → 手动改配置
哨兵方式:
┌─────────────────────────────────────────────┐
│ 1. 客户端连接 Sentinel 集群
│ 获取当前 Master 地址
│
│ 2. 客户端缓存 Master 地址
│ 正常读写
│
│ 3. Sentinel 检测到故障转移
│ 发布 +switch-master 消息
│
│ 4. 客户端收到通知
│ 断开旧连接,连接新 Master
│
│ 5. 若客户端未收到通知(网络问题)
│ 读写旧 Master 失败 → 重新向 Sentinel 查询
└─────────────────────────────────────────────┘
主流客户端支持:
• JedisSentinelPool(Java)
• redis-py-sentinel(Python)
• go-redis FailoverClient(Go)
• StackExchange.Redis(.NET)
数据一致性
┌─────────────────────────────────────────────────────────────┐
│ 异步复制带来的数据风险:
│
│ Master 写入数据 A ──► 未同步到 Slave ──► Master 宕机
│
│ 结果:
│ • 新 Master(原 Slave)没有数据 A
│ • 数据 A 丢失
│
│ 缓解方案:
│ • min-slaves-to-write 1 # 至少 1 个 Slave 同步才返回成功
│ • min-slaves-max-lag 10 # Slave 延迟不超过 10 秒
│
│ 代价:写入性能下降
└─────────────────────────────────────────────────────────────┘
优缺点
| 优点 | 缺点 |
|---|---|
| 自动故障转移,高可用 | 异步复制,故障转移时可能丢数据 |
| 客户端自动切换,透明 | 只有一个 Master,写性能无法扩展 |
| 配置简单,轻量级 | 脑裂风险(网络分区时可能双 Master) |
| 支持多组主从监控 | 不自动处理数据分片(需 Cluster 模式) |
与cluster对比
| 维度 | 哨兵模式 | Cluster 模式 |
|---|---|---|
| 数据分片 | 不支持 | 支持(16384 个 Slot) |
| 写扩展 | 单 Master | 多 Master |
| 读扩展 | 多 Slave | 多 Slave |
| 故障转移 | 自动 | 自动 |
| 复杂度 | 低 | 高 |
| 适用场景 | 数据量小、高可用 | 数据量大、高并发 |
总结
哨兵模式通过多 Sentinel 节点投票监控、领头选举、自动故障转移,在主从复制基础上实现了 Redis 的高可用。它解决了Master 宕机后手动切换的问题,但受限于单 Master 写性能和异步复制的数据一致性风险。