一、概述
1.1 背景介绍
Redis 主从复制解决了读扩展和数据冗余问题,但主节点故障时需要人工介入切换,这在生产环境中是不可接受的。Sentinel(哨兵)模式在主从架构之上增加了自动故障检测和故障转移能力,是 Redis 高可用的标准方案之一。
Sentinel 本质上是一组独立进程,持续监控 Redis 主从节点的健康状态,在主节点不可用时自动完成新主节点选举和客户端重定向。Redis 8.x 对 Sentinel 的稳定性和性能做了进一步优化,但核心机制与 7.x 保持一致。
1.2 技术特点
自动故障转移:主节点宕机后无需人工干预,Sentinel 集群自动完成切换,通常在 30 秒内完成
服务发现:客户端通过 Sentinel 获取当前主节点地址,屏蔽了主从切换的地址变化
配置传播:故障转移完成后,Sentinel 自动更新所有从节点的复制配置
多 Sentinel 协作:通过 quorum 机制避免单点误判,防止网络抖动触发不必要的切换
1.3 适用场景
数据量在单机可承载范围内(通常 < 100GB),不需要数据分片
对写入可用性要求高,能接受切换期间约 30 秒的写入中断
读写比高,通过从节点分担读流量
不需要 Cluster 的水平扩展能力,但需要比单主更高的可用性
1.4 环境要求
| 组件 | 版本要求 | 说明 |
|---|---|---|
| Redis | 8.x | 主从节点和 Sentinel 版本保持一致 |
| 操作系统 | Linux(内核 4.x+) | 需要稳定的网络栈 |
| 节点数量 | 最少 3 个 Sentinel | 保证 quorum 投票的奇数原则 |
| 网络延迟 | < 10ms(Sentinel 节点间) | 延迟过高影响故障检测准确性 |
二、详细步骤
2.1 Sentinel 工作原理
2.1.1 主观下线与客观下线
理解这两个概念是正确配置 Sentinel 的基础。
主观下线(SDOWN,Subjectively Down):单个 Sentinel 实例认为某节点不可用。判断依据是在down-after-milliseconds时间内没有收到节点的有效响应(PING 返回 PONG 或错误响应)。SDOWN 只是单个 Sentinel 的主观判断,不会触发故障转移。
客观下线(ODOWN,Objectively Down):多个 Sentinel 实例都认为主节点不可用,且达到 quorum 数量。只有主节点才有 ODOWN 状态,从节点和 Sentinel 节点只有 SDOWN。ODOWN 是触发故障转移的前提条件。
Sentinel A: PING master → 无响应 → 标记 master SDOWN Sentinel A: 询问 Sentinel B、C →"你们也认为 master 挂了吗?" Sentinel B:"是的,我也收不到响应" Sentinel C:"我也是" 达到 quorum=2 → Sentinel A 标记 master ODOWN → 开始 Leader 选举
2.1.2 故障转移流程
Leader 选举:Sentinel 集群通过 Raft 协议选出一个 Leader,由 Leader 负责执行故障转移
新主节点选择:Leader 从可用从节点中按以下优先级选择新主节点:
replica-priority(slave-priority)值最小的优先(0 表示永不成为主节点)
复制偏移量最大的优先(数据最新)
Run ID 字典序最小的优先(决胜条件)
执行切换:向选中的从节点发送REPLICAOF NO ONE,使其成为新主节点
重新配置:通知其他从节点复制新主节点,更新 Sentinel 配置文件
通知客户端:通过 Pub/Sub 频道+switch-master发布切换事件
2.2 3节点 Sentinel 集群配置
2.2.1 节点规划
节点角色 IP 端口 Redis 主节点 10.0.1.10 6379 Redis 从节点1 10.0.1.11 6379 Redis 从节点2 10.0.1.12 6379 Sentinel 1 10.0.1.10 26379 Sentinel 2 10.0.1.11 26379 Sentinel 3 10.0.1.12 26379
Sentinel 和 Redis 节点共用机器是常见的部署方式,节省资源。但要确保 Sentinel 进程和 Redis 进程的故障是独立的——Redis 挂了不代表 Sentinel 也挂。
2.2.2 Redis 主节点配置
# 文件路径:/etc/redis/redis.conf(主节点 10.0.1.10) bind 10.0.1.10 127.0.0.1 port 6379 daemonize yes pidfile /var/run/redis/redis-server.pid logfile /var/log/redis/redis-server.log dir /var/lib/redis # 持久化配置 save 900 1 save 300 10 save 60 10000 appendonly yes appendfsync everysec # 认证密码(主从和 Sentinel 必须一致) requirepass "Redis@Secure2024!" masterauth "Redis@Secure2024!" # 内存配置 maxmemory 8gb maxmemory-policy allkeys-lru # 脑裂防护:至少 1 个从节点同步才接受写入 min-replicas-to-write 1 min-replicas-max-lag 10
2.2.3 Redis 从节点配置
# 文件路径:/etc/redis/redis.conf(从节点 10.0.1.11 和 10.0.1.12) bind 10.0.1.11 127.0.0.1 # 10.0.1.12 节点改为对应 IP port 6379 daemonize yes logfile /var/log/redis/redis-server.log dir /var/lib/redis # 指定主节点 replicaof 10.0.1.10 6379 # 认证 requirepass "Redis@Secure2024!" masterauth "Redis@Secure2024!" # 从节点只读(默认已是 yes,显式声明更清晰) replica-read-only yes # 从节点优先级(数值越小越优先成为新主节点) # 10.0.1.11 设为 100,10.0.1.12 设为 200,优先选 .11 作为新主 replica-priority 100 # 持久化 appendonly yes appendfsync everysec
2.2.4 Sentinel 配置
三个 Sentinel 节点使用相同的配置文件,只有bind地址不同:
# 文件路径:/etc/redis/sentinel.conf # 三个节点分别修改 bind 为各自 IP bind 10.0.1.10 127.0.0.1 # 节点1;节点2改为10.0.1.11;节点3改为10.0.1.12 port 26379 daemonize yes pidfile /var/run/redis/redis-sentinel.pid logfile /var/log/redis/sentinel.log dir /var/lib/redis # 监控主节点,quorum=2 表示需要 2 个 Sentinel 同意才能触发故障转移 sentinel monitor mymaster 10.0.1.10 6379 2 # 主节点认证密码 sentinel auth-pass mymaster Redis@Secure2024! # 主节点超过 5000ms 无响应,标记为 SDOWN sentinel down-after-milliseconds mymaster 5000 # 故障转移超时时间:3 分钟内未完成则认为失败 sentinel failover-timeout mymaster 180000 # 故障转移后,同时向新主节点同步的从节点数量 # 设为 1 表示逐个同步,避免所有从节点同时不可读 sentinel parallel-syncs mymaster 1 # Sentinel 自身的访问密码(Redis 6.2+ 支持) requirepass "Sentinel@Secure2024!" sentinel sentinel-pass Sentinel@Secure2024!
2.2.5 启动顺序
# 1. 先启动主节点 systemctl start redis-server # 10.0.1.10 # 2. 启动从节点 systemctl start redis-server # 10.0.1.11 和 10.0.1.12 # 3. 验证主从复制状态 redis-cli -h 10.0.1.10 -p 6379 -a'Redis@Secure2024!'info replication # 预期输出关键字段: # role:master # connected_slaves:2 # slave0:ip=10.0.1.11,port=6379,state=online,offset=xxx,lag=0 # slave1:ip=10.0.1.12,port=6379,state=online,offset=xxx,lag=0 # 4. 启动 Sentinel(三个节点都要启动) redis-sentinel /etc/redis/sentinel.conf # 或 systemctl start redis-sentinel # 5. 验证 Sentinel 状态 redis-cli -h 10.0.1.10 -p 26379 -a'Sentinel@Secure2024!'sentinel masters
2.3 验证故障转移
# 模拟主节点故障 redis-cli -h 10.0.1.10 -p 6379 -a'Redis@Secure2024!'DEBUG sleep 30 # 在另一个终端观察 Sentinel 日志 tail -f /var/log/redis/sentinel.log # 预期日志序列: # +sdown master mymaster 10.0.1.10 6379 # +odown master mymaster 10.0.1.10 6379#quorum2/2 # +try-failover master mymaster 10.0.1.10 6379 # +elected-leader master mymaster 10.0.1.10 6379 # +selected-slave slave 10.0.1.11:6379 mymaster 10.0.1.10 6379 # +promoted-slave slave 10.0.1.11:6379 mymaster 10.0.1.10 6379 # +switch-master mymaster 10.0.1.10 6379 10.0.1.11 6379 # 故障转移完成后,查询新主节点 redis-cli -h 10.0.1.10 -p 26379 -a'Sentinel@Secure2024!'sentinel get-master-addr-by-name mymaster
三、示例代码和配置
3.1 客户端接入 Sentinel
客户端不能直连 Redis 主节点 IP,必须通过 Sentinel 获取当前主节点地址,否则主从切换后客户端无法自动重连。
3.1.1 Python(redis-py)
importredis
fromredis.sentinelimportSentinel
# 连接 Sentinel 集群
sentinel = Sentinel(
[
('10.0.1.10',26379),
('10.0.1.11',26379),
('10.0.1.12',26379),
],
socket_timeout=0.5,
sentinel_kwargs={'password':'Sentinel@Secure2024!'}
)
# 获取主节点连接(自动处理故障转移后的地址变更)
master = sentinel.master_for(
'mymaster',
socket_timeout=0.5,
password='Redis@Secure2024!',
db=0,
retry_on_timeout=True
)
# 获取从节点连接(读操作)
slave = sentinel.slave_for(
'mymaster',
socket_timeout=0.5,
password='Redis@Secure2024!',
db=0
)
# 写操作走主节点
master.set('key','value', ex=3600)
# 读操作走从节点
value = slave.get('key')
3.1.2 Java(Jedis)
importredis.clients.jedis.JedisSentinelPool; importredis.clients.jedis.Jedis; importredis.clients.jedis.JedisPoolConfig; importjava.util.HashSet; importjava.util.Set; // 配置连接池 JedisPoolConfig poolConfig =newJedisPoolConfig(); poolConfig.setMaxTotal(50); poolConfig.setMaxIdle(10); poolConfig.setMinIdle(5); poolConfig.setTestOnBorrow(true); // Sentinel 节点集合 Setsentinels =newHashSet<>(); sentinels.add("10.0.1.10:26379"); sentinels.add("10.0.1.11:26379"); sentinels.add("10.0.1.12:26379"); // 创建 Sentinel 连接池 JedisSentinelPool sentinelPool =newJedisSentinelPool( "mymaster", sentinels, poolConfig, 2000, // connectionTimeout 2000, // soTimeout "Redis@Secure2024!", // Redis 密码 0, // database null, // clientName 0, // sentinelConnectionTimeout 0, // sentinelSoTimeout "Sentinel@Secure2024!", // Sentinel 密码 null // sentinelClientName ); // 使用连接 try(Jedis jedis = sentinelPool.getResource()) { jedis.set("key","value"); String value = jedis.get("key"); }
3.2 Sentinel 监控脚本
#!/bin/bash
# 文件名:/opt/redis/scripts/sentinel_check.sh
# 功能:检查 Sentinel 集群健康状态,输出关键指标
SENTINEL_HOSTS=("10.0.1.10""10.0.1.11""10.0.1.12")
SENTINEL_PORT=26379
SENTINEL_PASS="Sentinel@Secure2024!"
MASTER_NAME="mymaster"
echo"===== Sentinel 集群状态检查 ====="
echo"时间:$(date)"
echo""
# 检查每个 Sentinel 节点
forhostin"${SENTINEL_HOSTS[@]}";do
echo"--- Sentinel:${host}:${SENTINEL_PORT}---"
# 获取当前主节点地址
master_info=$(redis-cli -h"${host}"-p"${SENTINEL_PORT}"
-a"${SENTINEL_PASS}"--no-auth-warning
sentinel get-master-addr-by-name"${MASTER_NAME}"2>/dev/null)
if[ $? -eq 0 ];then
master_ip=$(echo"${master_info}"| head -1)
master_port=$(echo"${master_info}"| tail -1)
echo" 当前主节点:${master_ip}:${master_port}"
else
echo" [ERROR] 无法连接 Sentinel"
continue
fi
# 获取 Sentinel 详细信息
sentinel_info=$(redis-cli -h"${host}"-p"${SENTINEL_PORT}"
-a"${SENTINEL_PASS}"--no-auth-warning
sentinel masters 2>/dev/null)
# 提取关键字段
num_slaves=$(echo"${sentinel_info}"| grep -A1"num-slaves"| tail -1)
num_sentinels=$(echo"${sentinel_info}"| grep -A1"num-other-sentinels"| tail -1)
quorum=$(echo"${sentinel_info}"| grep -A1"quorum"| tail -1)
flags=$(echo"${sentinel_info}"| grep -A1"^flags$"| tail -1)
echo" 从节点数量:${num_slaves}"
echo" 其他 Sentinel 数量:${num_sentinels}"
echo" Quorum:${quorum}"
echo" 主节点状态:${flags}"
echo""
done
3.3 脑裂防护配置详解
脑裂(Split-Brain)是 Sentinel 模式最危险的场景:主节点因网络分区与 Sentinel 失联,Sentinel 误判主节点宕机并选出新主节点,此时集群中存在两个主节点,客户端写入数据后,网络恢复时旧主节点的数据会被覆盖丢失。
# 在主节点 redis.conf 中配置 # 含义:至少有 1 个从节点在线且复制延迟不超过 10 秒,才接受写入 # 当主节点与所有从节点断开(网络分区场景),主节点自动拒绝写入 min-replicas-to-write 1 min-replicas-max-lag 10
这个配置的代价是:当从节点全部宕机或网络延迟超过 10 秒时,主节点会拒绝写入,业务会报错。这是一个可用性和一致性之间的权衡,对数据一致性要求高的场景(金融、订单)应该开启,对可用性优先的场景(缓存、会话)可以不开启。
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 Sentinel 节点部署
奇数原则:Sentinel 节点数量必须是奇数(3、5、7),quorum 设为(n/2)+1。3 节点集群 quorum=2,允许 1 个 Sentinel 故障;5 节点集群 quorum=3,允许 2 个故障。不要部署 2 个 Sentinel,quorum=2 时任意一个故障都会导致无法完成故障转移。
跨机架部署:3 个 Sentinel 节点分布在 3 个不同的物理机架或可用区,避免单机架故障导致 Sentinel 集群失去 quorum。
Sentinel 与 Redis 分离:资源充足时,Sentinel 进程部署在独立机器上,避免 Redis 进程消耗大量内存时影响 Sentinel 的心跳响应。
4.1.2 故障转移参数调优
down-after-milliseconds直接决定故障检测速度和误判率之间的平衡:
设置过小(< 3000ms):网络抖动、GC 停顿、系统负载高峰都可能触发误判
设置过大(> 30000ms):真实故障的检测时间过长,业务中断时间延长
推荐值:5000-10000ms,结合业务对中断时间的容忍度决定
4.1.3 持久化配置
Sentinel 模式下主从节点都应开启 AOF 持久化,appendfsync设为everysec。如果主节点关闭持久化,主节点重启后会以空数据集启动,从节点同步后数据全部丢失——这是一个经典的数据丢失场景。
4.2 注意事项
4.2.1 配置注意事项
警告:Sentinel 在完成故障转移后会自动修改sentinel.conf文件。如果用配置管理工具(Ansible、Chef)管理该文件,必须排除 Sentinel 自动写入的字段,否则下次配置推送会覆盖 Sentinel 的状态记录,导致集群状态混乱。
不要在 Sentinel 运行时手动编辑sentinel.conf
主从节点的requirepass和masterauth必须设置为相同的密码
故障转移完成后,原主节点恢复时会自动降级为从节点,不需要手动干预
4.2.2 常见错误
| 错误现象 | 原因分析 | 解决方案 |
|---|---|---|
| Sentinel 持续出现+sdown但不触发故障转移 | quorum 未达到,部分 Sentinel 节点无法通信 | 检查 Sentinel 节点间的网络连通性和防火墙规则 |
| 故障转移后客户端仍连接旧主节点 | 客户端硬编码了主节点 IP | 改造客户端使用 Sentinel 连接池 |
| 从节点复制延迟持续增大 | 主节点写入量超过从节点同步能力 | 增大repl_backlog_size,检查网络带宽 |
| Sentinel 选举超时,故障转移失败 | failover-timeout 设置过小 | 增大failover-timeout,检查 Sentinel 节点网络 |
4.3 Sentinel vs Cluster 选型
选 Sentinel 的场景:数据量在单机内存范围内、写入 QPS < 10 万、需要强一致的 Lua 脚本或事务操作。
选 Cluster 的场景:数据量超过单机内存、写入 QPS 超过单主节点瓶颈、需要线性扩展写入能力。
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看
# 实时查看 Sentinel 日志 tail -f /var/log/redis/sentinel.log # 查看最近的故障转移记录 grep"switch-master|failover|odown"/var/log/redis/sentinel.log | tail -50 # 查看主节点复制状态 redis-cli -h 10.0.1.10 -p 6379 -a'Redis@Secure2024!'info replication # 查看复制延迟(lag 字段,单位秒) redis-cli -h 10.0.1.10 -p 6379 -a'Redis@Secure2024!' info replication | grep"slave[0-9]"
5.1.2 常见问题排查
问题一:Sentinel 无法发现从节点
# 检查 Sentinel 已知的从节点列表 redis-cli -h 10.0.1.10 -p 26379 -a'Sentinel@Secure2024!' sentinel slaves mymaster # Sentinel 通过主节点的 INFO 命令发现从节点 # 如果从节点未出现,检查从节点的 replicaof 配置是否正确 redis-cli -h 10.0.1.11 -p 6379 -a'Redis@Secure2024!'info replication
问题二:故障转移后旧主节点无法加入集群
# 旧主节点恢复后,检查其角色 redis-cli -h 10.0.1.10 -p 6379 -a'Redis@Secure2024!'info replication # 如果仍显示 role:master,手动设置为从节点 redis-cli -h 10.0.1.10 -p 6379 -a'Redis@Secure2024!' replicaof 10.0.1.11 6379
5.2 性能监控
5.2.1 监控指标说明
| 指标名称 | 正常范围 | 告警阈值 | 说明 |
|---|---|---|---|
| 复制延迟(lag) | 0-1 秒 | > 10 秒 | 从节点数据落后主节点的时间 |
| connected_slaves | 等于从节点数 | < 预期数量 | 在线从节点数量 |
| Sentinel 响应时间 | < 5ms | > 100ms | Sentinel 进程健康状态 |
| master_last_io_seconds_ago | < 5 | > 30 | 主从最后通信时间间隔 |
| repl_backlog_active | 1 | 0 | 复制积压缓冲区是否活跃 |
5.3 备份与恢复
#!/bin/bash
# 从从节点备份,避免影响主节点性能
SLAVE_HOST="10.0.1.11"
REDIS_PASS="Redis@Secure2024!"
BACKUP_DIR="/opt/redis/backups"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p"${BACKUP_DIR}"
# 触发从节点 BGSAVE
redis-cli -h"${SLAVE_HOST}"-p 6379 -a"${REDIS_PASS}"--no-auth-warning BGSAVE
# 等待完成
sleep 5
# 复制 RDB 文件
cp /var/lib/redis/dump.rdb"${BACKUP_DIR}/dump_${DATE}.rdb"
echo"备份完成:${BACKUP_DIR}/dump_${DATE}.rdb"
# 保留最近 7 天
find"${BACKUP_DIR}"-name"dump_*.rdb"-mtime +7 -delete
六、总结
6.1 技术要点回顾
SDOWN vs ODOWN:单个 Sentinel 的主观判断不触发切换,需要达到 quorum 数量的 Sentinel 共同确认才进入客观下线状态
quorum 配置:3 节点集群设为 2,是可用性和防误判的最佳平衡点
脑裂防护:min-replicas-to-write让主节点在网络分区时主动拒绝写入,避免数据丢失
客户端接入:必须通过 Sentinel 发现主节点地址,不能硬编码 Redis 主节点 IP
replica-priority:通过优先级控制故障转移时的新主节点选择
6.2 进阶学习方向
Redis Cluster:当单主节点无法承载数据量或写入压力时,Cluster 是下一步演进方向
Sentinel 与 Proxy 结合:在 Sentinel 前部署 Twemproxy 或 Codis,对客户端屏蔽 Sentinel 发现逻辑
Redis 持久化深度优化:AOF rewrite 策略、RDB 与 AOF 混合持久化对故障恢复时间的影响
6.3 参考资料
Redis Sentinel 官方文档
Redis 8.x Release Notes
Redis 高可用架构设计
附录
A. 命令速查表
# 查询当前主节点地址 redis-cli -p 26379 -a'pass'sentinel get-master-addr-by-name mymaster # 查看所有主节点信息 redis-cli -p 26379 -a'pass'sentinel masters # 查看从节点列表 redis-cli -p 26379 -a'pass'sentinel slaves mymaster # 查看其他 Sentinel 节点 redis-cli -p 26379 -a'pass'sentinel sentinels mymaster # 手动触发故障转移(测试用) redis-cli -p 26379 -a'pass'sentinel failover mymaster # 重置 Sentinel 状态 redis-cli -p 26379 -a'pass'sentinel reset mymaster
B. 配置参数详解
| 参数 | 默认值 | 说明 |
|---|---|---|
| down-after-milliseconds | 30000 | 节点无响应多少毫秒后标记为 SDOWN |
| failover-timeout | 180000 | 故障转移超时时间(毫秒) |
| parallel-syncs | 1 | 故障转移后同时同步的从节点数量 |
| quorum | 需手动设置 | 触发 ODOWN 所需的最少 Sentinel 数量 |
| min-replicas-to-write | 0 | 主节点接受写入所需的最少在线从节点数 |
| min-replicas-max-lag | 10 | 从节点复制延迟超过此值(秒)视为不可用 |
C. 术语表
| 术语 | 英文 | 解释 |
|---|---|---|
| 主观下线 | SDOWN (Subjectively Down) | 单个 Sentinel 认为节点不可用 |
| 客观下线 | ODOWN (Objectively Down) | 多个 Sentinel 共同确认节点不可用 |
| 仲裁数 | Quorum | 触发故障转移所需的最少 Sentinel 同意数 |
| 脑裂 | Split-Brain | 网络分区导致集群中出现两个主节点的场景 |
| 复制积压 | Replication Backlog | 主节点保存的最近写命令缓冲区,用于断线重连后的增量同步 |
-
集群
+关注
关注
0文章
151浏览量
17684 -
组件
+关注
关注
1文章
600浏览量
19065 -
Redis
+关注
关注
0文章
394浏览量
12248
原文标题:Redis哨兵模式详解:自动故障检测与主从切换实战
文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
Redis的四种模式复制、哨兵、Cluster以及集群模式
谈谈Redis怎样配置实现主从复制?
什么是Redis主从复制
mysql主从复制三种模式
redis查看主从节点命令
Redis使用重要的两个机制:Reids持久化和主从复制
Redis实战笔记
Redis哨兵模式的自动故障检测与主从切换实战
评论