Skip to content

Redis 哨兵

本文介绍有关Redis哨兵监控相关知识。

1. 概述

在非Redis集群环境下,哨兵(Sentinel)可以为Redis提供高可用。主要作用如下:

  • 监控:哨兵可以不时检测Redis主从节点是否正常工作;
  • 通知:当被监控的Redis实例出问题时,哨兵可以发出通知;
  • 自动故障恢复:如果Redis主节点意外下线,哨兵可以启动自动故障恢复流程:选取一个从节点,将其提升为主节点,其他从节点自动重新配置跟随新的主节点,使用Redis的应用程序也会得到通知使用新的主节点;
  • 配置提供者:客户端连接到哨兵实例,查询负责特定服务的当前 Redis 主服务器的地址。如果发生故障转移(failover),哨兵会告知客户端新的主服务器地址。

2. 哨兵配置与启动

Sentinel配置文件下载地址:https://download.redis.io/redis-stable/sentinel.conf

Sentinel相关配置项如下:

  • port 26379:配置哨兵端口;
  • logfile xxx:配置日志文件;
  • sentinel monitor <master-name> <ip> <redis-port> <quorum>:设置哨兵监控的主节点
    • <master-name>:主节点名称,自己取,例如mymaster
    • <ip>:主节点IP地址;
    • <redis-port>:主节点端口;
    • <quorum>:它用于指定在主节点(master)发生故障时,至少需要多少个哨兵实例同意主节点确实不可用,才能进行自动故障转移(failover)操作。
  • sentinel auth-pass <master-name> <password>:设置哨兵节点访问主节点的密码;
    • <master-name>:主节点名称,与上面的相同;
    • <password>:主节点密码;

一份示例sentinel.conf文件如下:

txt
port 26379
logfile "/redis-sentinel/sentinel.log"

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 123456

有以下两种方式启动哨兵:

  • 方式一:使用redis-sentinel

    bash
    redis-sentinel /path/to/sentinel.conf
  • 方式二:使用redis-server

    bash
    redis-server /path/to/sentinel.conf --sentinel

本次使用Docker启动sentinel,请参考资料2。

启动命令如下:

txt
docker run --name redis-sentinel \
    -v /path/to/redis-sentinel/persistence:/bitnami \
    -p 26379:26379
    bitnami/redis-sentinel:latest

bitnami/redis-sentinel镜像会在/bitnami/redis-sentinel/conf/路径寻找配置文件,所以我们可以挂载宿主机目录到该路径。例如:

  • /projects/docker/sentinel01:并在该路径下的/redis-sentinel/conf/存放着有sentinel.conf配置文件。

3. 测试案例

3.1 一主二从结构

我们先使用Docker启动一主二从Redis实例。

DANGER

注意,由于主节点有可能变为从节点,从节点也有可能变成主节点,所以所有的主从节点都需要配置下面的选项:

txt
requirepass 123456
masterauth 123456

并且,主从节点的密码都要相同。

配置结果如下:

image-20250610161351714

3.2 启动哨兵节点

启动三个哨兵节点,监听26379端口,分别映射到宿主机26379,26380,26381端口。哨兵节点配置如下:

txt
port 26379
logfile "/bitnami/redis-sentinel/sentinel.log"

sentinel monitor mymaster 172.17.0.2 6379 2
sentinel auth-pass mymaster 123456

结果如下:

image-20250610162758721

3.3 主节点下线

关闭主节点所在容器,模拟主节点下线,然后,分别在三个节点的命令行界面查看信息:

image-20250611110810797

可以发现:

  • 其中一台从节点上位成为新的主节点;
  • 其他的从节点跟随新的主节点;

3.4 原主节点重新上线

我们重新启动原主节点,发现原主节点成为了从节点,跟随新的主节点:

image-20250611111405850

4. 原理解析

哨兵监控主要靠修改配置文件工作。

4.1 哨兵启动

三个哨兵节点依次启动,相关日志如下:

txt
1:X 11 Jun 2025 03:03:13.048 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:X 11 Jun 2025 03:03:13.048 * Redis version=7.4.3, bits=64, commit=00000000, modified=1, pid=1, just started
1:X 11 Jun 2025 03:03:13.048 * Configuration loaded
1:X 11 Jun 2025 03:03:13.049 * monotonic clock: POSIX clock_gettime
1:X 11 Jun 2025 03:03:13.049 * Running mode=sentinel, port=26379.
1:X 11 Jun 2025 03:03:13.050 * Sentinel new configuration saved on disk
1:X 11 Jun 2025 03:03:13.050 * Sentinel ID is 800e08c17595edb6b8e3ce0a89d5134ac15ba826
1:X 11 Jun 2025 03:03:13.050 # +monitor master mymaster 172.17.0.2 6379 quorum 2
1:X 11 Jun 2025 03:03:13.051 * +slave slave 172.17.0.3:6379 172.17.0.3 6379 @ mymaster 172.17.0.2 6379
1:X 11 Jun 2025 03:03:13.052 * Sentinel new configuration saved on disk
1:X 11 Jun 2025 03:03:13.052 * +slave slave 172.17.0.4:6379 172.17.0.4 6379 @ mymaster 172.17.0.2 6379
1:X 11 Jun 2025 03:03:13.053 * Sentinel new con figuration saved on disk
1:X 11 Jun 2025 03:03:43.053 * +sentinel sentinel 8c8ab9eb52610693bf699f29f1f7f58483f89f5e 172.17.0.6 26379 @ mymaster 172.17.0.2 6379
1:X 11 Jun 2025 03:03:43.054 * Sentinel new configuration saved on disk
1:X 11 Jun 2025 03:04:05.373 * +sentinel sentinel 7b59165baed59b231fd9fa5c926284adf9f6a907 172.17.0.7 26379 @ mymaster 172.17.0.2 6379
1:X 11 Jun 2025 03:04:05.377 * Sentinel new configuration saved on disk

主要记录了以下几件事:

  • 监测到Redis节点正在运行,如第1行;
  • 为该哨兵节点创建一个ID:Sentinel ID,如第7行 ;
  • 检测到从节点,如第9-12行;
  • 其他哨兵启动,监测到其他哨兵节点,如第13-16行;

4.2 启动时记录配置信息

在哨兵节点启动时,在日志中有很多下面的记录:

txt
Sentinel new configuration saved on disk

这句话的意思是会在哨兵节点配置文件sentinel.conf中记录相关配置信息,如:

txt
# Generated by CONFIG REWRITE
protected-mode no
latency-tracking-info-percentiles 50 99 99.9
dir "/"
user default on nopass sanitize-payload ~* &* +@all
sentinel myid 8c8ab9eb52610693bf699f29f1f7f58483f89f5e
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel current-epoch 1

sentinel known-replica mymaster 172.17.0.3 6379
sentinel known-replica mymaster 172.17.0.4 6379

sentinel known-sentinel mymaster 172.17.0.7 26379 7b59165baed59b231fd9fa5c926284adf9f6a907
sentinel known-sentinel mymaster 172.17.0.5 26379 800e08c17595edb6b8e3ce0a89d5134ac15ba826

主要关注三方面:

  • 记录本哨兵ID,如第6行;
  • 记录从节点地址,如第11-12行;
  • 记录其他哨兵地址和ID,如第14-15行;

4.3 主节点下线

当主节点下线后,查看哨兵节点日志:

txt
1:X 11 Jun 2025 03:05:36.312 # +sdown master mymaster 172.17.0.2 6379
1:X 11 Jun 2025 03:05:36.332 * Sentinel new configuration saved on disk
1:X 11 Jun 2025 03:05:36.333 # +new-epoch 1
1:X 11 Jun 2025 03:05:36.334 * Sentinel new configuration saved on disk
1:X 11 Jun 2025 03:05:36.334 # +vote-for-leader 8c8ab9eb52610693bf699f29f1f7f58483f89f5e 1
1:X 11 Jun 2025 03:05:36.387 # +odown master mymaster 172.17.0.2 6379 #quorum 3/2
1:X 11 Jun 2025 03:05:36.388 * Next failover delay: I will not start a failover before Wed Jun 11 03:11:36 2025
1:X 11 Jun 2025 03:05:37.671 # +config-update-from sentinel 8c8ab9eb52610693bf699f29f1f7f58483f89f5e 172.17.0.6 26379 @ mymaster 172.17.0.2 6379
1:X 11 Jun 2025 03:05:37.673 # +switch-master mymaster 172.17.0.2 6379 172.17.0.3 6379
1:X 11 Jun 2025 03:05:37.674 * +slave slave 172.17.0.4:6379 172.17.0.4 6379 @ mymaster 172.17.0.3 6379
1:X 11 Jun 2025 03:05:37.675 * +slave slave 172.17.0.2:6379 172.17.0.2 6379 @ mymaster 172.17.0.3 6379
1:X 11 Jun 2025 03:05:37.685 * Sentinel new configuration saved on disk
  • 如果某个哨兵 在指定时间(down-after-milliseconds)内未收到主节点的 PING 响应,则认为该节点主观下线。这称为主观下线(Subjectively Down,即sdown)。如第1行。

  • 当某个哨兵认为主节点不可用时,通过通过发布/订阅机制通知其他哨兵,检测主节点状态,如果此时主节点真的下线了,sdown的哨兵数超过quorum,则认为主节点客观下线(Objectively Down,即odown)了。

    从主观下线,到客观下线,是为了避免网络抖动等原因,使得单台哨兵节点未接收到主节点响应,误以为主节点下线从而发起故障恢复,只有哨兵集群中多数哨兵认为主节点下线了,才可以发起故障恢复。

    即主观下线是一台哨兵节点的判断,不可靠;客观下线是哨兵集群的判断,可靠。

  • 哨兵集群进行领导者选举,选择一个哨兵 负责执行故障转移:

    • 领导者哨兵选举日志如下:

      txt
      1:X 11 Jun 2025 03:05:36.331 # +vote-for-leader 8c8ab9eb52610693bf699f29f1f7f58483f89f5e 1
      1:X 11 Jun 2025 03:05:36.334 * 800e08c17595edb6b8e3ce0a89d5134ac15ba826 voted for 8c8ab9eb52610693bf699f29f1f7f58483f89f5e 1
      1:X 11 Jun 2025 03:05:36.335 * 7b59165baed59b231fd9fa5c926284adf9f6a907 voted for 8c8ab9eb52610693bf699f29f1f7f58483f89f5e 1

      该日志就是9f5e这个哨兵的日志,首先第一行表示自己给自己投票,后面两行表示其他哨兵也投票给自己,所以该哨兵称为领导者。

    • 选择其中某个从节点作为主节点,使用命令replicaof no one,并且将这个从节点的配置文件中有关从属关系配置删除;

    • 其他从节点跟随新的主节点,使用命令replicaof <host> <port>,修改这些从节点的配置文件,改为新的主节点;

    • 修改原主节点的配置文件,使其跟随新的主节点;

  • 哨兵节点也要更新相关配置,更新从节点信息。

4.4 原主节点重新上线

由于更改了配置文件,原主节点重新上线,也就成为了从节点。

5. 相关算法

5.1 领导者选举算法

领导者选举算法,主要是使用了Raft算法的变种。主要流程如下:

  • 发起选举

    • 当某个哨兵发现主节点已经客观下线后,它会尝试发起一次领导者选举;
    • 该哨兵会将自己的 epoch加 1,并向其他哨兵发送命令,请求它们投票给自己,表明自己想成为 Leader;
  • 投票过程

    • 每个哨兵在一个 epoch 内只能投一票

    • 当一个哨兵 收到投票命令时:

      • 如果它尚未在当前 epoch 内投过票,并且请求投票的哨兵的 epoch 大于或等于自己的 epoch,那么它会同意投票给请求者;
      • 它会将自己结构体中的 leaderleader_epoch 字段更新为投票给的哨兵和其 epoch
      • 如果它已经投过票给其他哨兵,或者请求者的 epoch 小于自己的 epoch,它将拒绝投票。

      请求投票的哨兵收到其他哨兵的投票后,会记录这些投票。

  • Leader 选举成功

    • 如果一个哨兵收到了超过半数的哨兵投票,它就被选举为 Leader。
    • 一旦选举出 Leader,该 Leader就负责执行后续的故障转移流程。

5.2 从节点提升算法

如果有多个从节点,哨兵领导者如何从多个从节点中选出一个,使其成为主节点呢?

  • 首先,在配置文件redis.conf中,replica-priority配置项的值越低,优先级越高;

    如果replica-priority的值为0,则表示该从节点不会被选为主节点。

  • 如果优先级相同,则Replication Offset越大的从节点,则表示其从主节点接收并执行到的命令越多,数据一致性更好,应该被选择;

  • 经过上面两步,仍然有多个从节点满足条件,则具有较小的Run ID的从节点应该被选择。

6. 注意事项

  • 哨兵节点的数量应为多个,保证高可用;
  • 哨兵节点的数量应为奇数;
  • 各个哨兵节点的配置应该相同,包括物理配置;
  • 哨兵集群+主从复制的架构,并不能保证数据零丢失;

参考资料

[1] redis sentinel:https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/

[2] bitnami redis-sentinel:https://hub.docker.com/r/bitnami/redis-sentinel