问题
Redis的哨兵模式是什么?
答案
1. 核心概念
Redis Sentinel(哨兵模式)是Redis官方提供的高可用解决方案,通过监控主从节点,在主节点故障时自动完成故障转移(Failover),无需人工介入。
核心功能:
- 监控(Monitoring):持续检测主从节点和其他哨兵节点是否正常运行
- 通知(Notification):当监控的实例出现问题时,通过API发送通知
- 自动故障转移(Automatic Failover):主节点故障时,自动将从节点升级为主节点,并通知客户端
- 配置提供者(Configuration Provider):客户端连接哨兵获取当前主节点地址
2. 哨兵模式架构
+----------------+
| Client |
+-------+--------+
|
| (1) 获取主节点地址
v
+----------+----------+----------+
| | | |
[Sentinel1] [Sentinel2] [Sentinel3] (哨兵集群,至少3个)
| | |
+----------+----------+----------+
|
(2) 监控主从节点
|
+-----------+-----------+
| |
[Master] [Slave1] [Slave2]
| ^
+------- 主从复制 -------+
关键要点:
- 哨兵集群:通常部署奇数个(3/5/7个),通过投票机制保证决策的可靠性
- 客户端连接:客户端不直接连接Redis节点,而是先从哨兵获取主节点地址
- 独立进程:哨兵是独立的Redis进程,但只使用监控和管理功能
3. 哨兵模式工作原理
3.1 监控机制
每个哨兵节点会执行以下任务:
1. 每10秒向主从节点发送 INFO 命令
- 发现主从拓扑结构
- 获取从节点信息和复制状态
2. 每2秒向所有节点的 __sentinel__:hello 频道发送消息
- 交换哨兵之间的信息
- 发现其他哨兵节点
3. 每1秒向主从节点和其他哨兵发送 PING 命令
- 检测节点是否存活
- 判断是否主观下线
3.2 故障检测与判定
主观下线(SDOWN - Subjectively Down):
- 单个哨兵认为节点下线
- 条件:哨兵在配置的
down-after-milliseconds时间内未收到有效PING回复
# 哨兵配置示例
sentinel monitor mymaster 192.168.1.100 6379 2 # 至少2个哨兵同意才能故障转移
sentinel down-after-milliseconds mymaster 5000 # 5秒未响应判定主观下线
客观下线(ODOWN - Objectively Down):
- 多个哨兵(达到quorum数量)认为节点下线
- 流程:
- 哨兵A检测到主节点主观下线
- 哨兵A向其他哨兵发送
SENTINEL is-master-down-by-addr命令询问 - 收到quorum个确认后,判定主节点客观下线
- 触发故障转移流程
3.3 自动故障转移流程
完整流程:
// 伪代码描述故障转移流程
public class SentinelFailover {
public void execute() {
// 1. 选举领头哨兵(Leader Election)
Sentinel leader = electLeader(); // Raft算法,先到先得
// 2. 领头哨兵从从节点中选出新主节点
Slave newMaster = selectNewMaster();
// 3. 向新主节点发送 SLAVEOF NO ONE 命令,升级为主节点
newMaster.execute("SLAVEOF NO ONE");
// 4. 向其他从节点发送 SLAVEOF <new_master_ip> <port>,改变复制目标
for (Slave slave : otherSlaves) {
slave.execute("SLAVEOF " + newMaster.ip + " " + newMaster.port);
}
// 5. 更新哨兵配置,记录新主节点信息
updateSentinelConfig(newMaster);
// 6. 持续监控旧主节点,恢复后降级为从节点
monitorOldMaster();
}
}
关键步骤详解:
1️⃣ 选举领头哨兵:
- 使用Raft算法的简化版本
- 先发起选举的哨兵成为候选者,向其他哨兵请求投票
- 每个哨兵只投票一次,先到先得
- 获得超过半数投票的哨兵成为Leader
2️⃣ 选出新主节点(详见后续”选主策略”):
- 优先级高的从节点优先
- 复制偏移量大的从节点优先(数据最新)
- runID最小的从节点优先
3️⃣ 通知客户端:
- 哨兵通过发布/订阅机制向客户端发送
+switch-master消息 - 客户端(如Jedis、Lettuce)自动连接新主节点
4. 哨兵配置与部署
4.1 哨兵配置文件(sentinel.conf)
# 监控的主节点(mymaster是别名,2是quorum值)
sentinel monitor mymaster 192.168.1.100 6379 2
# 主节点密码
sentinel auth-pass mymaster <password>
# 主观下线判定时间(毫秒)
sentinel down-after-milliseconds mymaster 5000
# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 60000
# 同时向新主节点发起复制的从节点数量(并行度)
sentinel parallel-syncs mymaster 1
# 拒绝连接的客户端IP(可选)
sentinel deny-scripts-reconfig yes
4.2 启动哨兵
# 方式1:使用redis-sentinel命令
redis-sentinel /path/to/sentinel.conf
# 方式2:使用redis-server并指定sentinel模式
redis-server /path/to/sentinel.conf --sentinel
5. 客户端集成
5.1 Jedis集成示例
import redis.clients.jedis.JedisSentinelPool;
public class SentinelClient {
public static void main(String[] args) {
// 哨兵节点地址集合
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.1.10:26379");
sentinels.add("192.168.1.11:26379");
sentinels.add("192.168.1.12:26379");
// 创建哨兵连接池
JedisSentinelPool pool = new JedisSentinelPool(
"mymaster", // 主节点名称
sentinels, // 哨兵节点集合
"password" // Redis密码
);
// 获取连接(自动连接当前主节点)
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
System.out.println(jedis.get("key"));
}
pool.close();
}
}
客户端工作原理:
- 连接任意哨兵节点,发送
SENTINEL get-master-addr-by-name mymaster获取主节点地址 - 连接主节点进行读写操作
- 订阅哨兵的
+switch-master频道,监听主节点变化 - 故障转移时,自动切换到新主节点
6. 性能优化与注意事项
6.1 哨兵数量选择
- 最少3个:支持一个哨兵故障时仍能正常工作
- 推荐5个:支持两个哨兵故障,适合生产环境
- 避免偶数:偶数个哨兵可能出现选举平票,影响决策效率
6.2 quorum与majority的区别
- quorum:判定主节点客观下线需要的哨兵数量(配置文件中设置)
- majority:选举领头哨兵需要的投票数(哨兵总数 / 2 + 1)
示例:
- 5个哨兵,quorum=2:2个哨兵认为下线即可触发故障转移,但需要3个投票才能选出Leader
- 生产建议:quorum = 哨兵总数 / 2 + 1
6.3 脑裂问题
场景:
- 网络分区导致旧主节点与哨兵失联
- 哨兵将从节点升级为新主节点
- 旧主节点仍接受写请求,导致数据丢失
解决方案:
# 主节点至少有N个从节点连接才允许写入
min-replicas-to-write 1
# 从节点延迟小于N秒才算有效连接
min-replicas-max-lag 10
7. 面试答题总结
标准回答模板:
Redis哨兵模式是官方的高可用解决方案,通过多个哨兵节点(建议3/5个)监控主从节点,实现:
- 监控:每秒PING检测节点存活,每10秒INFO获取拓扑结构
- 故障检测:单个哨兵检测到主观下线(SDOWN)后,询问其他哨兵,达到quorum数量判定客观下线(ODOWN)
- 自动故障转移:选举领头哨兵(Raft算法)→ 选出新主节点(优先级、复制偏移量、runID)→ 通知客户端切换
核心配置:
sentinel monitor <name> <ip> <port> <quorum>:监控主节点,quorum为判定下线的投票数sentinel down-after-milliseconds:主观下线判定时间(建议5秒)客户端集成:通过JedisSentinelPool等连接哨兵,自动获取主节点地址并监听切换事件
常见追问:
- 哨兵如何发现其他哨兵? → 通过向
__sentinel__:hello频道发布消息 - 领头哨兵如何选举? → Raft算法简化版,先发起选举的获得投票,超过半数即成为Leader
- quorum和majority的区别? → quorum判定下线,majority选举Leader(哨兵总数/2+1)