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 端口的指令,让原主节点成为新主的从节点,实现自动归队,保证拓扑的一致性。