Redis 哨兵(sentinel)
一、定义
1. 基本概念
Redis Sentinel(哨兵)是 Redis 官方提供的高可用(HA)解决方案,专门用于解决 Redis 主从架构中主节点宕机后的自动化故障转移问题,同时提供主节点的监控、通知、自动故障恢复、配置中心能力。
2. 核心定位
- 监控 + 自动故障转移 + 主从统一入口 + 配置同步
3. 部署形态
- 生产环境必须集群化部署哨兵(至少 3 个),杜绝单点故障
二、工作原理
哨兵的工作流程是循环执行的,整体分为 3 大核心阶段,底层依赖「心跳检测」「主观下线」「客观下线」「投票选举」「故障转移」5 个核心机制。
1. 哨兵的初始化与基础监控(常驻)
- 哨兵启动后,会和配置的主节点建立 TCP 连接,分为 2 类:命令连接(发送 info、config 等指令)、订阅连接(订阅 sentinel:hello 频道)
- 通过主节点的 info replication 指令,自动发现所有从节点,并与所有从节点建立相同的 2 类连接
- 哨兵集群内的所有节点,通过 sentinel:hello 频道互相感知,自动组成哨兵集群,无需手动配置其他哨兵地址
- 哨兵会定时发送心跳包:每隔 1 秒向主/从节点发送 PING 指令,每隔 10 秒向主节点发送 info 指令更新拓扑,每隔 2 秒通过频道发送自己的节点信息
2. 故障判定(主观下线 + 客观下线)
(1)主观下线(SDOWN,Subjectively Down)
1)定义
单个哨兵节点检测到目标主节点在指定时间内(down-after-milliseconds)持续无 PONG 响应,该哨兵就认为主节点「主观下线」。
2)本质
单机的“一面之词”,可能是网络抖动、主节点繁忙导致,不会触发故障转移。
(2)客观下线(ODOWN,Objectively Down)
1)定义
哨兵集群中,超过指定数量的哨兵节点都认为同一个主节点主观下线,此时达成共识,判定主节点「客观下线」。
2)触发条件
满足投票的哨兵数 ≥ quorum 配置值,且投票的哨兵都是集群内的有效节点。
3)核心
客观下线是触发故障转移的唯一前置条件,主节点才会进入故障转移流程,从节点不会有客观下线的概念。
3. 故障转移
当主节点被判定为客观下线后,哨兵集群会选举出 1 个领头哨兵,由该哨兵执行完整的故障转移流程。
(1)选举领头哨兵(leader)
哨兵集群通过「Raft 算法」选举出一个主哨兵,负责执行故障转移,保证只有 1 个哨兵执行转移操作,杜绝脑裂。
(2)筛选合格从节点
遍历所有从节点,剔除:
- 主观下线的从节点
- 与主节点失联过久的从节点
- 优先级为 0 的从节点(永不被选为主节点)
(3)选举新主节点
对筛选后的从节点,按优先级排序,优先级越高越优先;优先级相同则选偏移量(offset)最大的(数据最全);偏移量相同则选 runid 最小的。
(4)执行主从切换
领头哨兵向选中的从节点发送 slaveof no one 指令,使其升级为主节点。
(5)从节点重新挂载
- 领头哨兵向其他所有从节点发送 slaveof 新主节点 IP 端口,让所有从节点同步新主
- 同时更新哨兵集群的主节点配置,通知客户端
- 原宕机主节点恢复后,会被哨兵设置为新主的从节点,实现自动归队
三、常用配置(sentinel.conf)
1. sentinel monitor mymaster 192.168.1.100 6379 2
- 2 是 quorum 值(至少 2 个哨兵判定主节点主观下线,才会客观下线)
- 哨兵数 ≥ 3 时,quorum 值设为 哨兵数/2 + 1
2. sentinel auth-pass mymaster 12345678
- master 节点的登录密码
3. sentinel down-after-milliseconds mymaster 30000
- 判定主观下线的超时时间,单位 ms,默认 30000(30 秒)
4. sentinel failover-timeout mymaster 180000
- 故障转移的超时时间,默认 180 秒;如果超过该时间转移未完成,则终止本次转移,等待下次重试
5. sentinel auth-pass mymaster 123456
- 如果 Redis 主节点配置了密码,哨兵必须配置该项,否则无法连接主从节点
6. sentinel parallel-syncs mymaster 1
- 故障转移后,同时向新主节点同步数据的从节点数,默认 1
- 值越大,从节点同步越快,但新主节点的压力越大,生产建议保持 1,避免新主被打满
7. daemonize yes
- 哨兵后台运行,生产必开
8. pidfile /var/run/redis-sentinel.pid
- 哨兵进程的 pid 文件路径,防止端口占用
9. logfile “”
- 日志文件路径,生产必须配置,方便排查故障
四、常用操作
1. 查询类
- sentinel masters:查看所有被监控的主节点信息
- sentinel master mymaster:查看指定名称的主节点详细信息
- sentinel replicas mymaster:查看指定主节点的所有从节点信息
- sentinel sentinels mymaster:查看监控该主节点的所有哨兵节点信息
- sentinel get-master-addr-by-name mymaster:生产最常用,获取当前主节点的 IP + 端口,客户端可通过该指令实现主节点的动态发现
2. 故障转移类
- sentinel failover mymaster:手动触发故障转移,不会触发主观/客观下线,直接选举新主,生产用于「主节点升级」「手动切换主从」,无数据丢失风险
- sentinel reset mymaster:重置指定主节点的状态,清除下线标记,用于「误判下线后的恢复」
- sentinel remove mymaster:让哨兵停止监控该主节点
3. 其他类
- redis-sentinel /usr/local/redis/conf/sentinel.conf:启动哨兵
- redis-cli -p 26379:登录哨兵节点
- redis-cli -p 26379 shutdown:关闭哨兵(哨兵关闭后,其他哨兵会自动感知)
五、操作示例
1. 查看哨兵信息
# 主节点
127.0.0.1:26380> SENTINEL masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6380"
7) "runid"
8) ""
9) "flags"
10) "s_down,master,disconnected"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "365752"
17) "last-ok-ping-reply"
18) "365753"
19) "last-ping-reply"
20) "912"
21) "s-down-time"
22) "325159"
23) "down-after-milliseconds"
24) "30000"
25) "info-refresh"
26) "0"
27) "role-reported"
28) "master"
29) "role-reported-time"
30) "365753"
31) "config-epoch"
32) "0"
33) "num-slaves"
34) "0"
35) "num-other-sentinels"
36) "0"
37) "quorum"
38) "2"
39) "failover-timeout"
40) "180000"
41) "parallel-syncs"
42) "1"
2. 主从复制模拟故障
- master 写入数据,然后 kill
- 查看哨兵和复制状态
# 6381 查看,master 已切换
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6382
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:85287
slave_repl_offset:85287
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1
master_total_sync_attempts:1
master_link_up_since_seconds:64
total_disconnect_time_sec:1023
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:17f825685fb65822320be24bc66ac45797d7875b
master_replid2:b8287c8b46431d8cdf5735b9c30a695a2ef8f698
master_repl_offset:85287
second_repl_offset:72364
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1319
repl_backlog_histlen:83969
# 哨兵查看
127.0.0.1:26380> SENTINEL GET-MASTER-ADDR-BY-NAME mymaster
1) "127.0.0.1"
2) "6382"
- 旧的 master 重新启动
redis-server /data/redis/cluster/redis-6380/redis.conf
- 查看复制状态
# 原 master 变成了 slave
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6382
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_read_repl_offset:72363
slave_repl_offset:72363
replica_full_sync_buffer_size:0
replica_full_sync_buffer_peak:0
master_current_sync_attempts:1404
master_total_sync_attempts:1404
master_link_down_since_seconds:-1
total_disconnect_time_sec:0
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:68aa8b764b0fb942257440998220bc8caa634591
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:72363
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
六、业务场景
1. 读写分离的业务
主节点写,从节点读,哨兵解决主节点宕机后的自动切换,满足 99.99% 的业务高可用需求。
2. 数据量不大的场景
单 Redis 实例的内存 ≤ 10G,主从同步无压力,哨兵的故障转移足够高效。
3. 对一致性要求中等的场景
缓存、排行榜、计数器、会话存储、消息队列(非核心)等,哨兵的最终一致性完全满足。
4. 架构轻量化的需求
哨兵部署简单,无额外依赖,相比 Redis Cluster,运维成本极低,中小团队首选。
5. 异地多活的轻量方案
跨机房的主从架构,哨兵可实现跨机房的故障转移。
七、选型
1. 小数据量 + 高可用 + 低运维成本 → 哨兵
2. 大数据量 + 分片 + 高并发 → Redis Cluster
八、注意事项
1. 部署层面
- 哨兵集群必须至少部署 3 个节点,且哨兵节点的数量为奇数
- 哨兵节点必须和 Redis 主从节点「分机部署」
- Redis 主从节点的 replica-read-only yes(从节点只读)必须开启:防止从节点被写入数据,导致主从数据不一致,哨兵故障转移后数据丢失
2. 配置层面
- quorum 值的配置原则:quorum = 哨兵数 / 2 + 1
- 从节点的 replica-priority 合理配置:对「备份节点」设置优先级为 0,永不被选为主节点;对「核心从节点」设置高优先级,保证故障转移后的数据完整性
- 主节点的密码必须统一
- 禁止修改哨兵的默认端口 26379
3. 数据一致性层面
(1)数据丢失风险及解决方案
- 风险:哨兵的故障转移是「最终一致性」,存在少量数据丢失的风险。原因是主节点宕机时,可能有部分写请求还未同步到从节点,故障转移后新主节点没有这部分数据。
- 解决方案:主节点配置 repl-diskless-sync no(磁盘同步);配置 min-replicas-to-write 1 + min-replicas-max-lag 10,主节点在从节点同步超时/数量不足时,拒绝写入(Redis 8.4 默认开启该兜底策略)。
(2)脑裂问题的处理
- 现象:主节点因为网络分区,被哨兵判定为下线,选举了新主,但原主节点实际存活,此时出现「双主」。
- 解决方案:主节点配置 replica-announce-ip + replica-announce-port(这两个参数用于上报访问地址),同时开启 min-replicas-to-write,原主节点会因为从节点数不足而拒绝写入;Redis 8.4 优化了脑裂后的自动归队逻辑,原主节点恢复后会立即成为新主的从节点。
4. 运维层面
- 哨兵的日志必须开启
- 禁止手动修改 Redis 的主从关系,所有主从切换必须由哨兵执行,否则哨兵的配置会和实际拓扑不一致
- 哨兵节点的版本必须和 Redis 主从节点一致
九、面试题
1. Redis 哨兵的作用是什么
- 监控:实时监控主从节点的健康状态
- 自动故障转移:主节点宕机后,自动选举新主,切换从节点的挂载关系
- 通知:向客户端/运维人员发送节点状态变更的告警
- 配置中心:客户端可通过哨兵获取当前主节点的地址,实现动态发现
2. 什么是主观下线和客观下线?区别是什么?
- 主观下线是单个哨兵判定主节点无响应,是单机的判断,可能是网络抖动;客观下线是哨兵集群中超过 quorum 数的哨兵都判定主节点主观下线,达成共识,是触发故障转移的唯一条件。
- 从节点只有主观下线,没有客观下线。
3. 哨兵集群为什么要部署奇数个节点?
- 防止投票平票:奇数个节点可以保证在选举领头哨兵时,不会出现票数相等的情况,能快速选出领头节点
- 容错性更高:3 个哨兵可以容忍 1 个哨兵宕机,5 个哨兵可以容忍 2 个宕机,偶数个节点的容错性更低
- 减少资源浪费:奇数个节点是性价比最高的部署方式
4. 哨兵选举新主节点的规则是什么?
- 剔除不合格的从节点(下线、失联过久、优先级 0)
- 按从节点优先级排序,值越小优先级越高
- 优先级相同则选数据偏移量(offset)最大的(数据最全)
- 偏移量相同则选 runid 最小的
5. Redis 哨兵的故障转移流程是什么?
- 哨兵集群判定主节点客观下线
- 通过 Raft 算法选举出领头哨兵
- 筛选合格的从节点
- 按规则选举新主节点,执行 slaveof no one
- 其他从节点挂载到新主,原主恢复后成为新主的从节点
6. 哨兵的故障转移会导致数据丢失吗?为什么?如何解决?
- 会丢失少量数据,原因有 2 点:主节点宕机时,部分写请求还未同步到从节点,新主没有这部分数据;脑裂时原主节点的写请求无法同步到新主。
- 解决方案:主节点配置 min-replicas-to-write 1 和 min-replicas-max-lag 10,从节点同步超时/数量不足时拒绝写入;开启主节点的持久化,防止重启后数据丢失。
7. 哨兵和 Redis Cluster 的区别?各自的适用场景?
(1)核心区别
- 功能:哨兵是主从的高可用方案,无分片能力;Cluster 是分片 + 高可用方案,支持海量数据存储
- 部署:哨兵部署简单,运维成本低;Cluster 部署复杂,需要至少 6 个节点(3 主 3 从)
- 一致性:哨兵是最终一致性;Cluster 是分片内的最终一致性
(2)适用场景
- 哨兵适合小数据量、读写分离、低运维成本的场景
- Cluster 适合大数据量、高并发写入、需要分片的场景
8. 哨兵的 parallel-syncs 配置的作用是什么?值越大越好吗?
- 该配置是故障转移后,同时向新主同步数据的从节点数。
- 值越大,从节点同步完成的速度越快,但新主节点的网络和 CPU 压力越大,容易导致新主节点卡顿,生产建议设为 1。
9. 哨兵选举领头哨兵的算法是什么?(Raft 算法)
哨兵选举领头哨兵使用的是简化版的 Raft 算法,核心规则:
- 只有判定主节点客观下线的哨兵才有资格发起选举
- 哨兵向其他节点发送投票请求,其他节点如果还未投票,则投给该哨兵
- 获得超过半数选票的哨兵成为领头哨兵
- 如果选举超时,则重新发起选举,直到选出领头哨兵
10. 如果哨兵集群全部宕机,Redis 主从节点还能正常工作吗?
可以正常工作。哨兵只是监控和故障转移的进程,Redis 主从节点的核心功能不受哨兵影响,主节点依然可以写,从节点依然可以读和同步数据。只是当主节点宕机后,无法自动触发故障转移,需要手动执行 slaveof no one 切换主从。
11. 主节点恢复后,为什么会自动成为新主的从节点?
因为哨兵在故障转移后,会更新自己的配置,记录新主节点的地址。当原主节点恢复后,哨兵会检测到该节点存活,并且发现该节点不是当前的主节点,于是向原主节点发送 slaveof 新主 IP 端口的指令,让原主节点成为新主的从节点,实现自动归队,保证拓扑的一致性。