【Redis】哨兵机制Day10

写在前面

主从复制解决了数据冗余和读写分离的问题,但主节点故障时需要人工干预切换,这在生产环境中是不可接受的。Redis哨兵(Sentinel)机制实现了主节点的自动故障转移,是Redis高可用的核心组件。今天我们深入理解哨兵机制的原理与实践。

文章目录


一、为什么需要哨兵?

1.1 主从架构的痛点

实际场景:某公司Redis主节点在凌晨3点宕机,运维人员收到告警后手动切换主从,整个过程耗时30分钟,期间服务不可用,造成严重的业务损失。

主从架构存在的问题:

问题 说明
单点故障 主节点宕机后无法写入
人工干预 故障切换需要人工操作
切换时间长 人工响应慢,服务中断时间长
配置变更 切换后需要修改应用配置

1.2 哨兵的作用

Redis Sentinel提供以下功能:

功能 说明
监控 持续检查主从节点是否正常运行
通知 节点故障时通知管理员或其他应用
自动故障转移 主节点故障时自动选举新主节点
配置提供者 为客户端提供当前主节点地址
仲裁者 多个哨兵共同决策,避免误判
复制代码
┌─────────────────────────────────────────────────────────┐
│                     Sentinel Cluster                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │Sentinel-1│  │Sentinel-2│  │Sentinel-3│              │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘              │
│       │             │             │                     │
│       └─────────────┼─────────────┘                     │
│                     │ 监控 & 投票                        │
└─────────────────────┼───────────────────────────────────┘
                      │
         ┌────────────┼────────────┐
         ▼            ▼            ▼
  ┌──────────┐ ┌──────────┐ ┌──────────┐
  │  Master  │ │  Slave1  │ │  Slave2  │
  └──────────┘ └──────────┘ └──────────┘

二、哨兵的核心功能

2.1 监控(Monitoring)

哨兵定期向主从节点发送心跳检测:

检测类型 频率 说明
PING 每秒 检测节点是否存活
INFO 每10秒 获取主从拓扑信息
PUBLISH 每2秒 发布哨兵信息到__sentinel__:hello频道

主观下线(S_DOWN):

  • 单个哨兵认为节点下线
  • 配置:down-after-milliseconds

客观下线(O_DOWN):

  • 多数哨兵认为主节点下线
  • 触发故障转移流程

2.2 通知(Notification)

哨兵可以通过以下方式通知故障:

redis 复制代码
# 订阅哨兵频道
SUBSCRIBE __sentinel__:hello

# 订阅故障转移事件
SUBSCRIBE +switch-master
SUBSCRIBE +sdown
SUBSCRIBE +odown

2.3 自动故障转移(Automatic Failover)

故障转移流程:

复制代码
┌──────────────────────────────────────────────────────────┐
│                    故障转移流程                           │
├──────────────────────────────────────────────────────────┤
│  1. 哨兵检测到主节点客观下线                              │
│                    ↓                                     │
│  2. 哨兵之间投票选举领导者哨兵                            │
│                    ↓                                     │
│  3. 领导者哨兵从从节点中选举新主节点                       │
│                    ↓                                     │
│  4. 其他从节点复制新主节点                                │
│                    ↓                                     │
│  5. 更新主节点配置,通知客户端                            │
│                    ↓                                     │
│  6. 旧主节点恢复后变为从节点                              │
└──────────────────────────────────────────────────────────┘

2.4 配置提供者(Configuration Provider)

客户端连接哨兵获取主节点地址:

redis 复制代码
# 客户端请求主节点地址
SENTINEL get-master-addr-by-name mymaster

# 返回
1) "192.168.1.101"
2) "6379"

三、哨兵配置详解

3.1 哨兵配置文件

conf 复制代码
# sentinel.conf

# 端口
port 26379

# 监控主节点
# sentinel monitor <master-name> <ip> <port> <quorum>
sentinel monitor mymaster 192.168.1.100 6379 2

# 主节点密码
sentinel auth-pass mymaster your_password

# 主观下线时间
sentinel down-after-milliseconds mymaster 30000

# 故障转移超时时间
sentinel failover-timeout mymaster 180000

# 同时可以对新主节点进行复制的从节点数量
sentinel parallel-syncs mymaster 1

# 工作目录
dir "/var/redis/sentinel"

# 日志级别
loglevel notice

# 日志文件
logfile "/var/log/redis/sentinel.log"

# 后台运行
daemonize yes

# PID文件
pidfile "/var/run/redis-sentinel.pid"

3.2 配置参数说明

参数 说明 默认值
quorum 判断客观下线需要的哨兵数量 -
down-after-milliseconds 主观下线时间 30000ms
failover-timeout 故障转移超时时间 180000ms
parallel-syncs 同时复制的从节点数 1

3.3 quorum配置详解

经验之谈:quorum的配置需要根据哨兵数量合理设置,一般设置为哨兵数量的半数以上。

quorum的作用:

  • 判断主节点是否客观下线
  • 选举领导者哨兵时需要多数哨兵同意

推荐配置:

哨兵数量 quorum 说明
1 1 不推荐,单点故障
3 2 推荐,允许1个哨兵故障
5 3 推荐,允许2个哨兵故障

3.4 启动哨兵

shell 复制代码
# 方式一:使用配置文件启动
redis-sentinel /etc/redis/sentinel.conf

# 方式二:使用redis-server启动
redis-server /etc/redis/sentinel.conf --sentinel

四、哨兵选举原理

4.1 领导者哨兵选举

当主节点被判定为客观下线后,需要选举一个领导者哨兵来执行故障转移。

选举流程:

复制代码
┌─────────────────────────────────────────────────────────┐
│                领导者哨兵选举流程                        │
├─────────────────────────────────────────────────────────┤
│  1. 发现主节点客观下线的哨兵成为候选者                    │
│                    ↓                                    │
│  2. 候选者向其他哨兵发送SENTINEL is-master-down-by-addr │
│                    ↓                                    │
│  3. 其他哨兵收到请求后,每个epoch只投票一次               │
│                    ↓                                    │
│  4. 获得多数票的候选者成为领导者哨兵                     │
│                    ↓                                    │
│  5. 领导者哨兵执行故障转移                              │
└─────────────────────────────────────────────────────────┘

选举规则:

  • 使用Raft算法进行选举
  • 每个配置纪元(epoch)只能投票一次
  • 获得多数票的哨兵成为领导者

4.2 新主节点选举

领导者哨兵从从节点中选举新主节点,选举规则:

优先级 规则 说明
1 排除下线节点 不选择已下线的从节点
2 排除断开时间长的节点 down-after-milliseconds * 10
3 优先级配置 replica-priority值小的优先
4 复制偏移量 slave_repl_offset大的优先
5 runid runid小的优先(兜底)

从节点配置优先级:

conf 复制代码
# 从节点配置
replica-priority 100    # 数值越小优先级越高,0表示不参与选举

五、故障转移详细流程

5.1 完整故障转移流程

复制代码
时间线
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 1. 哨兵检测到主节点主观下线                  │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 2. 多数哨兵确认,主节点客观下线              │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 3. 哨兵之间投票选举领导者哨兵                │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 4. 领导者哨兵选择新主节点                    │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 5. 新主节点执行 REPLICAOF NO ONE            │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 6. 其他从节点复制新主节点                    │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 7. 更新哨兵配置,发布切换事件                │
  │  └─────────────────────────────────────────────┘
  │
  │  ┌─────────────────────────────────────────────┐
  │  │ 8. 旧主节点恢复后变为从节点                  │
  │  └─────────────────────────────────────────────┘
  ▼

5.2 客户端感知

客户端通过以下方式感知主节点变化:

方式一:订阅事件

redis 复制代码
# 订阅主节点切换事件
SUBSCRIBE +switch-master

# 收到消息格式
# +switch-master
# mymaster
# 192.168.1.100 6379    # 旧主节点
# 192.168.1.101 6379    # 新主节点

方式二:主动查询

redis 复制代码
# 获取当前主节点地址
SENTINEL get-master-addr-by-name mymaster

方式三:连接池自动发现

java 复制代码
// Jedis示例
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.1.100:26379");
sentinels.add("192.168.1.101:26379");
sentinels.add("192.168.1.102:26379");

JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
Jedis jedis = pool.getResource();  // 自动获取当前主节点

六、踩坑提醒

踩坑提醒:脑裂问题

问题描述:

网络分区导致主节点与哨兵隔离,哨兵选举出新主节点,但旧主节点仍在接收写入,导致数据不一致。

复制代码
┌─────────────────────────────────────────────────────────┐
│                      网络分区                            │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   ┌─────────────┐          │          ┌─────────────┐  │
│   │  旧 Master  │          │          │  新 Master  │  │
│   │  (隔离区)    │          │          │  (多数区)    │  │
│   └─────────────┘          │          └─────────────┘  │
│         │                  │                │          │
│         ▼                  │                ▼          │
│   ┌─────────────┐          │          ┌─────────────┐  │
│   │   Client    │          │          │   Client    │  │
│   │  (写入旧主)  │          │          │  (写入新主)  │  │
│   └─────────────┘          │          └─────────────┘  │
│                                                         │
└─────────────────────────────────────────────────────────┘

解决方案:

conf 复制代码
# 主节点配置
# 至少有1个从节点才能写入
min-replicas-to-write 1

# 从节点延迟不超过10秒
min-replicas-max-lag 10

配置说明:

  • 如果从节点数量不足或延迟过高,主节点拒绝写入
  • 防止网络分区时旧主节点继续接收写入
  • 恢复后旧主节点的数据会被新主节点覆盖

踩坑提醒:哨兵数量不足

问题描述:

哨兵数量为2个时,一个哨兵故障后无法进行故障转移(无法达到多数票)。

解决方案:

  • 哨兵数量至少3个,建议奇数个(3、5、7)
  • 哨兵部署在不同服务器上

踩坑提醒:配置文件覆盖

问题描述:

哨兵运行时会自动修改配置文件,记录主从拓扑变化。如果手动修改配置文件可能被覆盖。

解决方案:

  • 哨兵配置文件需要可写权限
  • 修改配置后重启哨兵
  • 使用SENTINEL RESET命令重置配置

七、哨兵监控与运维

7.1 常用命令

redis 复制代码
# 查看主节点信息
SENTINEL master mymaster

# 查看从节点列表
SENTINEL replicas mymaster

# 查看哨兵列表
SENTINEL sentinels mymaster

# 获取主节点地址
SENTINEL get-master-addr-by-name mymaster

# 检查主节点是否下线
SENTINEL is-master-down-by-addr 192.168.1.100 6379

# 强制故障转移
SENTINEL failover mymaster

# 重置哨兵配置
SENTINEL RESET mymaster

7.2 监控指标

指标 说明 告警阈值
master_link_status 主从连接状态 down
slave_repl_offset 从节点复制偏移量 与主节点差距大
s_down 主观下线 触发告警
o_down 客观下线 触发告警
num-other-sentinels 其他哨兵数量 少于预期

7.3 运维建议

建议 说明
哨兵数量 至少3个,奇数个
部署位置 不同服务器,跨机房部署
监控告警 监控主从状态、复制延迟
配置备份 定期备份哨兵配置文件
测试演练 定期进行故障转移演练

八、面试高频考点

考点1:哨兵如何判断主节点下线?

答案:

两步判断:

  1. 主观下线(S_DOWN)

    • 单个哨兵在down-after-milliseconds时间内未收到主节点PONG响应
    • 标记为主观下线
  2. 客观下线(O_DOWN)

    • 当主观下线的哨兵数量达到quorum配置值
    • 标记为客观下线,触发故障转移

    哨兵1: 主观下线 ────┐
    哨兵2: 主观下线 ────┼───> 客观下线 (quorum=2)
    哨兵3: 正常 ────┘

考点2:哨兵如何选举新主节点?

答案:

选举规则(按优先级):

  1. 排除不健康节点:下线或断开时间长的节点
  2. 优先级配置replica-priority值小的优先
  3. 复制偏移量slave_repl_offset大的优先(数据最新)
  4. runid:runid小的优先(兜底规则)

配置示例:

conf 复制代码
# 从节点配置
replica-priority 100    # 优先级,数值越小越优先

考点3:哨兵的数量如何配置?

答案:

哨兵数量 quorum 容错能力 说明
1 1 0 不推荐
2 1 0 不推荐
3 2 1 推荐
5 3 2 推荐

原则:

  • 哨兵数量 ≥ 3,且为奇数
  • quorum = 哨兵数量 / 2 + 1
  • 允许故障的哨兵数量 = 哨兵数量 - quorum

考点4:什么是脑裂?如何解决?

答案:

脑裂问题:

网络分区导致旧主节点与多数哨兵隔离,哨兵选举出新主节点,但旧主节点仍在接收写入,造成数据不一致。

解决方案:

conf 复制代码
# 主节点配置
min-replicas-to-write 1    # 至少有1个从节点才能写入
min-replicas-max-lag 10    # 从节点延迟不超过10秒

原理:

  • 网络分区后,旧主节点失去从节点连接
  • 配置条件不满足,旧主节点拒绝写入
  • 避免数据不一致

九、参考资料

Redis官方文档 - Sentinel


十、互动话题

  1. 你的生产环境哨兵是如何部署的?遇到过什么问题?
  2. 如何设计一个跨机房的哨兵架构?需要考虑哪些因素?
  3. 哨兵故障转移过程中,客户端如何保证写入不丢失?

欢迎在评论区分享你的经验和见解!


恭喜你完成了Redis系列文章的学习!希望这个系列对你的Redis学习和面试有所帮助!

相关推荐
陈随易13 小时前
FFmpeg 9.0 发布,代号 Lei,音视频处理再升级
前端·后端·程序员
凌虚16 小时前
面向 MySQL 用户的 PostgreSQL 快速上手指南
数据库·后端·架构
五阿哥永琪17 小时前
MySQL中操作json的函数!
数据库·mysql·json
来者皆善17 小时前
了解Mysql优化吗?如何优化索引?
数据库·mysql
IT_陈寒18 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端
前端开发张小七18 小时前
Java 学习笔记 · 第一课:基础语法与核心概念
java·后端
海盗123418 小时前
微软技术周报 ——2026-08-03
后端·python·microsoft·c#·.netcore
沙湖遇雨18 小时前
6. Pipeline 的生命周期
后端
ai_coder_ai18 小时前
分布式缓存架构设计与实践
分布式·缓存
凡尘——雨落凡尘18 小时前
PHP 线上十大隐形故障复盘:90% 的网站卡顿、502、雪崩,都是这些细节导致的
redis·nginx·php·session