Redis Sentinel 是 Redis 官方提供的高可用(HA)解决方案。在单纯的主从复制架构里,一旦主节点宕机,必须人工介入把某个从节点提升为主节点、再修改所有客户端连接,既慢又容易出错。Sentinel 通过一组独立的哨兵进程,持续监控主从节点健康状况,在主库失联时自动完成故障转移(failover)并把新拓扑推送给客户端,让 Redis 服务在无人值守下自愈。本文从为什么需要、如何部署、故障转移原理到客户端接入与常见坑,完整落地一套稳定的哨兵高可用方案。
一、为什么需要 Sentinel
主从复制解决了数据冗余与读扩展,却没有解决”主节点失效”的问题。一旦主库挂掉,写请求会全部失败,运维需要手动执行 replicaof no one 提升从库、再逐个修改应用配置——在深夜或大规模集群里,这个恢复时间(RTO)往往以分钟甚至小时计。Sentinel 的价值正在于此:它把”发现故障→选举新主→切换拓扑→通知客户端”整条链路自动化,把人工操作变成秒级自愈。
理解 Sentinel 的前提是先有可用的主从复制。如果你还没搭建一主多从,建议先参考 Redis 主从复制相关实践,再在其之上叠加哨兵层。Sentinel 本身不存储数据,它只是”旁观者+指挥官”,真正的读写仍由 Redis 数据节点承担。
二、Sentinel 的四个职责
每个 Sentinel 进程同时承担四类工作:监控(定期 ping 节点判断是否存活)、通知(通过 API 把故障事件告知外部)、自动故障转移(主库下线后选新主并重组复制关系)、配置提供(客户端向哨兵查询当前主节点地址)。正因为故障转移和客户端寻址都由哨兵负责,应用代码里写死的 IP 才得以解耦。
三、部署哨兵集群:最少三个节点
哨兵采用”多数派”决策,因此必须部署奇数个(至少 3 个)且分布在独立机器或容器内,避免单点。每个哨兵的配置极其简单,核心是声明要监控哪个主节点。
# sentinel.conf(每个哨兵节点内容基本一致)
port 26379
sentinel monitor mymaster 10.0.0.10 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1
# 最后的数字 2 是 quorum:至少 2 个哨兵认为主库下线才触发客观下线
用 Docker 启动时把配置挂载进去即可,三个哨兵指向同一主节点名 mymaster。哨兵之间会自动发现彼此(通过主节点上的发布订阅频道),无需手动互配。
# 启动哨兵(容器方式)
docker run -d --name sentinel1 \
-v $(pwd)/sentinel.conf:/etc/redis/sentinel.conf \
redis:7 redis-sentinel /etc/redis/sentinel.conf
# 三个节点分别启动 sentinel1 / sentinel2 / sentinel3
四、哨兵如何判定故障:SDOWN 与 ODOWN
哨兵对节点的判定分两级:主观下线(SDOWN)是单个哨兵在 down-after-milliseconds 内没收到有效回复,认为”我看它挂了”;客观下线(ODOWN)则是达到 quorum 数量的哨兵都标记 SDOWN 后,由哨兵集群共同确认”它真的挂了”。只有进入 ODOWN,才会发起故障转移。这套多数派机制有效避免了网络抖动导致的误切换。
# 查看哨兵对主节点的认知
redis-cli -p 26379 INFO sentinel
# 或查询主节点状态
redis-cli -p 26379 SENTINEL master mymaster
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 返回当前主节点 IP:PORT,客户端据此连接
五、故障转移流程
当主节点被判定 ODOWN,哨兵集群会先选出一个”领导者”(Raft 式协商)来执行转移,避免多个哨兵同时操作。领导者从剩余从节点里挑一个数据最新、优先级最高的提升为新主,让其他从节点改为复制新主,最后把新拓扑写回并通知所有客户端。整个过程通常在十几秒内完成,期间写请求短暂不可用。
# 模拟主库宕机观察自动转移
# 1) 找到当前主节点
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 2) 杀掉该主节点进程
# 3) 等待约 (down-after + failover-timeout) 后再次查询
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 输出应已变为新的从节点地址 —— 说明故障转移成功
六、客户端如何接入哨兵
应用不应直连固定 IP,而要连接哨兵并询问”当前主节点是谁”。主流 Redis 客户端都内置了哨兵支持。下面以 Java 的 Lettuce 为例:
// Java(Lettuce)通过哨兵发现主节点
RedisURI uri = RedisURI.Builder
.sentinel("10.0.0.10", 26379, "mymaster")
.withSentinel("10.0.0.11", 26379)
.withSentinel("10.0.0.12", 26379)
.build();
RedisClient client = RedisClient.create(uri);
StatefulRedisConnection<String, String> conn = client.connect();
Lettuce 会在后台订阅哨兵事件,主节点切换后自动重连到新主,业务代码无感知。同样地,Jedis 也有 JedisSentinelPool 可用。关键在于:把”找主节点”这件事交给客户端与哨兵的协议,而不是写死在配置里。
七、Sentinel 与 Redis Cluster 的区别
很多人混淆 Sentinel 与 Cluster。简单说,Sentinel 解决的是”高可用”(主从故障自动切换),数据仍是单分片;Cluster 解决的是”水平扩展”(数据分片到多主)并自带故障转移。若数据量未超单机内存,Sentinel 更简单;若需分片扩容,才上 Cluster。两者并非替代关系,甚至可以叠加。
| 维度 | Redis Sentinel | Redis Cluster |
|---|---|---|
| 核心目标 | 高可用 / 故障转移 | 分片扩展 / 高可用 |
| 数据分布 | 单分片(一主多从) | 16384 槽多主分片 |
| 客户端寻址 | 哨兵查询主节点 | 计算槽位直连对应主 |
| 适用规模 | 数据不超单机内存 | 需要水平扩容 |
八、生产环境常见坑
| 现象 | 根因 | 对策 |
|---|---|---|
| 误切换 | down-after 太小 / 网络抖动 | 调大到 5–10s,确保 quorum 多数 |
| 脑裂丢数据 | 主库假死仍接受写 | 设 min-replicas-to-write 限制 |
| 哨兵自己单点 | 只部署 1–2 个 | 必须 ≥3 且奇数、分散主机 |
| 客户端连旧主 | 未用哨兵寻址 | 改用哨兵模式连接池 |
| failover 卡住 | parallel-syncs 过高 | 设为 1,逐个同步减压 |
还要特别注意:哨兵节点的数量必须奇数,才能在网络分区时形成多数派;quorum 一般设为 (哨兵数/2)+1。若主库与哨兵处于同一故障域(如同一台物理机),则失去冗余意义。这些参数在Redis Stream 消息队列 或Redis 核心数据结构 等实践里用到的 Redis 实例,只要上了生产都应套一层哨兵保护。
九、监控与告警
哨兵自身也要被监控。通过 INFO sentinel 可拿到主从数量、故障转移次数、各节点状态;建议把”主节点地址变化””odown 事件””剩余从节点数”接入 Prometheus 或告警系统。结合Redis 缓存击穿与雪崩防护 的监控思路,能在缓存层与高可用层同时守住稳定性。另外,故障转移后旧主重启会作为从节点自动挂回新主,无需手动干预,但仍要确认其数据已追平。
十、小结
Redis Sentinel 用极简配置换来生产级高可用:三节点哨兵监控主从,靠 SDOWN/ODOWN 多数派判定避免误切换,由选举出的领导者自动提升新主并通知客户端。它和 Redis Cluster 解决不同问题——前者保活、后者分片,按需选用。落地时牢记三条铁律:哨兵数必为奇数且分散、quorum 取多数、客户端务必走哨兵寻址而非写死 IP。把这套机制与Redis 数据结构选型、缓存防护 组合,才是完整的 Redis 生产稳定性方案。




