引言
主从复制虽然实现了数据备份,但主节点宕机后需要手动切换。哨兵(Sentinel)提供了自动故障检测和故障转移能力,实现真正的高可用。
一、哨兵概述
1.1 什么是哨兵?
监控
↓
[哨兵1] ←→ [哨兵2] ←→ [哨兵3] (多个哨兵相互通信)
↓ ↓ ↓
监控 监控 监控
↓ ↓ ↓
[主节点] ← [从节点1] ← [从节点2]
功能:
1. 监控:检查主从节点是否正常
2. 通知:故障通知管理员
3. 故障转移:自动提升从节点为主节点
4. 配置中心:客户端通过哨兵发现主节点
1.2 核心功能
监控(Monitoring)
- 检查主从节点健康状态
- 周期性发送PING命令
故障检测(Failure Detection)
- 主观下线(SDOWN):单个哨兵判断
- 客观下线(ODOWN):多数哨兵同意
自动故障转移(Failover)
- 选举领导者哨兵
- 选择新主节点
- 通知从节点切换
- 通知客户端
配置中心(Configuration Provider)
- 客户端从哨兵获取主节点地址
- 主节点变更自动通知客户端
二、哨兵部署
2.1 最小配置
# sentinel.conf
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2 # 2个哨兵同意才判定下线
sentinel down-after-milliseconds mymaster 5000 # 5秒无响应判断下线
sentinel failover-timeout mymaster 180000 # 故障转移超时时间
sentinel parallel-syncs mymaster 1 # 同时同步的从节点数量
2.2 启动哨兵
# 方式1:
redis-sentinel sentinel.conf
# 方式2:
redis-server sentinel.conf --sentinel
# 查看哨兵状态
127.0.0.1:26379> SENTINEL masters
127.0.0.1:26379> SENTINEL slaves mymaster
127.0.0.1:26379> SENTINEL sentinels mymaster
2.3 推荐部署架构
机器1:Redis Master + Sentinel1
机器2:Redis Slave1 + Sentinel2
机器3:Redis Slave2 + Sentinel3
好处:
- 3个哨兵互相监控,防止误判
- 分布式部署,避免单点故障
三、故障检测机制
3.1 主观下线(SDOWN)
哨兵1每秒向主节点发送PING:
PING → 主节点
PING → 主节点
PING → (超时5秒无响应)
判断:主节点主观下线(SDOWN)
配置:
sentinel down-after-milliseconds mymaster 5000
3.2 客观下线(ODOWN)
哨兵1询问其他哨兵:
↓
"你们认为主节点下线了吗?"
↓
哨兵2:是的 |
哨兵3:是的 | → 2个哨兵同意(达到quorum=2)
↓
判断:主节点客观下线(ODOWN)
配置:
sentinel monitor mymaster 127.0.0.1 6379 2 # quorum=2
四、故障转移流程
4.1 选举领导者哨兵
哨兵1检测到主节点客观下线:
↓
向其他哨兵发起投票:
"我要成为领导者,负责故障转移"
↓
哨兵2投票:同意
哨兵3投票:同意
↓
哨兵1获得多数票,成为领导者(Leader)
Raft算法:确保只有一个领导者
4.2 选择新主节点
选择规则:
- 剔除下线和断线的从节点
- 选择优先级最高的(replica-priority)
- 优先级相同,选择offset最大的(数据最新)
- offset相同,选择runid最小的
从节点1:priority=100, offset=1000, runid=aaa
从节点2:priority=100, offset=1200, runid=bbb
从节点3:priority=50, offset=1100, runid=ccc
选择:从节点3(优先级最高)
4.3 提升新主节点
领导者哨兵执行:
↓
1. 向从节点3发送:REPLICAOF NO ONE
(从节点变为主节点)
↓
2. 向从节点1、2发送:REPLICAOF <新主节点IP> <新主节点端口>
(指向新主节点)
↓
3. 更新哨兵配置:记录新主节点信息
↓
4. 通知其他哨兵:更新主节点信息
↓
5. 通知客户端:主节点地址已变更
4.4 旧主节点恢复
旧主节点恢复后:
↓
哨兵检测到旧主节点上线
↓
发送命令:REPLICAOF <新主节点IP> <新主节点端口>
↓
旧主节点变为从节点
五、客户端配置
5.1 Jedis示例
import redis.clients.jedis.JedisSentinelPool;
// 配置哨兵连接
Set<String> sentinels = new HashSet<>();
sentinels.add("127.0.0.1:26379");
sentinels.add("127.0.0.1:26380");
sentinels.add("127.0.0.1:26381");
JedisSentinelPool pool = new JedisSentinelPool(
"mymaster", // 主节点名称
sentinels, // 哨兵列表
poolConfig // 连接池配置
);
// 使用
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
String value = jedis.get("key");
}
// 原理:
// 1. 客户端向哨兵询问主节点地址
// 2. 哨兵返回当前主节点信息
// 3. 客户端连接主节点
// 4. 主节点故障时,哨兵通知客户端新主节点地址
5.2 Spring Boot配置
spring:
redis:
sentinel:
master: mymaster
nodes:
- 127.0.0.1:26379
- 127.0.0.1:26380
- 127.0.0.1:26381
password: yourpassword
六、最佳实践
6.1 哨兵数量
✅ 推荐:
- 奇数个哨兵(3个或5个)
- 最少3个哨兵(防止单点故障)
❌ 避免:
- 2个哨兵(无法达成多数)
- 偶数个哨兵(可能脑裂)
6.2 quorum设置
quorum = (哨兵数量 / 2) + 1
示例:
- 3个哨兵 → quorum=2
- 5个哨兵 → quorum=3
原则:确保多数哨兵同意才触发故障转移
6.3 网络分区
场景:
网络故障:
机房A | 机房B
[主节点] (网络断开) [从节点1]
[哨兵1] | [从节点2]
[哨兵2] | [哨兵3]
问题:
- 哨兵1、2检测不到主节点 → 判断下线
- 哨兵3仍能连接主节点 → 认为正常
解决:
- quorum=2(多数原则)
- 哨兵1、2达成共识,触发故障转移
- 提升从节点1或2为新主节点
6.4 避免频繁切换
# 增大down-after-milliseconds(避免误判)
sentinel down-after-milliseconds mymaster 30000 # 30秒
# 增大failover-timeout(避免重复故障转移)
sentinel failover-timeout mymaster 180000 # 3分钟
七、监控与告警
7.1 关键指标
127.0.0.1:26379> INFO sentinel
sentinel_masters:1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=mymaster,status=ok,slaves=2,sentinels=3
监控项:
- 主从节点状态(ok/down)
- 哨兵数量(确保多数在线)
- 故障转移次数(频繁切换需排查)
7.2 日志分析
# 故障检测
+sdown master mymaster 127.0.0.1 6379 # 主观下线
+odown master mymaster 127.0.0.1 6379 #quorum 2/2 # 客观下线
# 故障转移
+failover-state-select-slave master mymaster # 选择从节点
+selected-slave slave 127.0.0.1:6380 # 选中从节点
+failover-state-send-slaveof-noone slave 127.0.0.1:6380 # 提升主节点
+switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380 # 切换完成
八、总结
核心要点
哨兵作用
- 监控主从节点
- 自动故障转移
- 配置中心
故障检测
- 主观下线(单个哨兵)
- 客观下线(多数哨兵)
故障转移流程
- 选举领导者哨兵
- 选择新主节点
- 提升新主节点
- 通知客户端
最佳实践
- 奇数个哨兵(3或5)
- quorum = (N/2) + 1
- 分布式部署
客户端
- 通过哨兵自动发现主节点
- 故障转移对客户端透明
下一篇预告
哨兵解决了高可用问题,但单个主节点的容量有限。如何实现水平扩展?Cluster集群如何分片?
下一篇《Cluster集群:分片与容错》,我们将深入Redis集群模式。