【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学习和面试有所帮助!

相关推荐
鲨鱼辣椒喔1 小时前
# 团队密码管理工具怎么选?对比 Bitwarden、Vault、Excel 和 OpsTiny
运维·数据库·安全·密码学·个人开发
学编程的小程1 小时前
配置范式演进:XML、JavaConfig 与 Spring Boot
xml·spring boot·后端
Elastic 中国社区官方博客1 小时前
Elasticsearch Reindex 现已支持跨节点自动迁移:无需人工干预,不会丢失进度
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
努力努力再努力wz1 小时前
【C++高阶数据结构系列】:跳表 SkipList 详解:多层索引、随机晋升与C++ 完整实现(附跳表实现的源码)
开发语言·数据结构·数据库·c++·redis·缓存·skiplist
学代码的真由酱1 小时前
MySQL数据库进阶-Java
数据库·mysql
Devin~Y1 小时前
从Spring Boot到AI Agent:大厂Java微服务面试三轮实战问答解析
java·spring boot·redis·spring cloud·微服务·ai·kafka
码不停蹄的玄黓1 小时前
SpringBoot 循环依赖解决方案
java·spring boot·后端
暗夜猎手-大魔王1 小时前
转载--Hermes Agent 09 | 技能安全:静态扫描 + 信任级别策略如何防止“技能投毒“
网络·数据库·安全
Surpass-HC1 小时前
gsoap搭建网络像机onvif服务器
linux·服务器·数据库