Redis 高可用架构之哨兵模式 – Sentinel

  • 1. 前言
  • 2. Redis Sentinel 哨兵集群搭建
    • 2.1 一主两从
    • 2.2 三个哨兵
  • 3. Redis Sentinel 原理剖析
    • 3.1 什么哨兵模式
    • 3.2 哨兵机制的主要任务
      • 3.2.1 监控
        • (1)每1s发送一次 PING 命令
        • (2)PING 命令的回复有两种情况
        • (3)主观下线和客观下线
      • 3.2.2 主从动态切换
        • (1)筛选
        • (2)综合评估
      • 3.2.3 通知
    • 3.3 哨兵机制的工作原理
      • 3.3.1 pub/sub 实现哨兵间通信和发现 slave
      • 3.3.2 选择哨兵执⾏主从切换
      • 3.3.3 通过 pub/sub 实现客户端事件通知
  • 4. 总结
    • 4.1 哨兵主要任务
    • 4.2 哨兵集群原理

1. 前言

上一篇文章,已经介绍了 Redis 主从架构:Redis 主从复制 + 读写分离。为Redis 配置主从模式,可以大幅度提高 Redis 的可用性,减少甚至避免 Redis 服务发生宕机的可能。

Redis 主从模式有以下作用:

  • 故障隔离和恢复:无论主节点或者从节点宕机,其他节点依然可以保证服务的正常运行,并可以手动切换主从。
  • 读写隔离:Master 节点提供写服务,Slave 节点提供读服务,分摊流量压力,均衡流量的负载。
  • 提供高可用保障:主从模式是高可用的最基础版本,也是哨兵模式和 cluster模式实施的前置条件。

尽管 Redis 主从模式已经做的足够多了,但其还是存在不小的问题。我们先来学习一个专业名词:平均修复时间(Mean time to repair,MTTR),它是衡量系统可用性的关键指标:我们计算一下,从监控到 Redis 故障到手动切换主从止损,再到 Redis 服务恢复正常,这期间可能是一个较长的过程,这在生产环境(甚至是超高并发的大型交易系统)就是一个灾难,其带来的损失也是无法估计的。

所以我们需要系统自动的感知到 Master 故障,并选择一个 Slave 切换为 Master,实现故障自动转移的能力。

2. Redis Sentinel 哨兵集群搭建

在这里插入图片描述

2.1 一主两从

  • Master
bind 0.0.0.0
# Master 端口
port 6379
# 后台执行
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis1.log"
dbfilename "pointer1.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly1.aof"
masterauth "123456"

  • Slave

主要在于端口号不同,分别是 6380、6381。

bind 0.0.0.0
# Master 端口
port 6380
# 后台执行
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis2.log"
dbfilename "pointer2.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly2.aof"
# 从本机 6379 的 redis 实例复制数据,Redis 5.0 之前使用 slaveof
replicaof 192.169.0.1 6379
# 从节点开启只读模式(默认)
replica‐read‐only yes
# 从节点访问主节点的密码,和 requirepass ⼀样
masterauth "123456"

  • 分别启动 Redis
./redis-6.2.4/src/redis-server redis-6379/redis.conf
./redis-6.2.4/src/redis-server redis-6380/redis.conf
./redis-6.2.4/src/redis-server redis-6381/redis.conf

2.2 三个哨兵

将哨兵配置文件分别复制到 sentinel26379 sentinel26380 sentinel26381,需要注意的是每个文件的端口配置以及 sentinel monitor mymaster 192.169.0.1 6379 2 中最后的数字 2,哨兵集群汇总每个节点必须一致。

  • 分别修改这三个配置文件:
# 绑定IP
bind 0.0.0.0
# 后台运行
daemonize yes
# 默认yes,没指定密码或者指定IP的情况下,外网无法访问
protected-mode no
# 哨兵的端口,客户端通过这个端口来发现redis
port 26379
# 这个文件会自动生成(如果同一台服务器上启动,注意要修改为不同的端口)
pidfile /var/run/redis-sentinel-26379.pid
# sentinel 监控的 master 的名字叫做 mymaster,初始地址为 127.0.0.1 6379,2代表两个及以上哨兵认定为故障,才认为是真的故障
sentinel monitor mymaster 192.169.0.1 6379 2

  • 启动哨兵集群
./redis-6.2.4/src/redis-sentinel sentinel26379/sentinel.conf
./redis-6.2.4/src/redis-sentinel sentinel26380/sentinel.conf
./redis-6.2.4/src/redis-sentinel sentinel26381/sentinel.conf

  • 查看 sentinel 监控的 master-slave 信息:
redis-cli -h 192.168.0.1 -p 26379
sentinel master mymaster
SENTINEL replicas mymaster
SENTINEL sentinels mymaster

  • 测试故障自动转移
redis-cli -p 6379 DEBUG sleep 30

  • 再次检查当前 master 地址,这次将得到不同的响应:
SENTINEL get-master-addr-by-name mymaster

  • 13. Redis Sentinel 原理剖析

3.1 什么哨兵模式

哨兵是 Redis 的⼀种运⾏模式,它专注于对 Redis 实例(主节点、从节点)运⾏状态的监控,并能够在主节点发⽣故障时通过⼀系列的机制实现选主及主从切换,实现故障转移,确保整个 Redis 系统的可⽤性。

  1. Redis提供了哨兵的命令,是⼀个独⽴的进程
  2. 哨兵通过发送命令给多个节点,等待 Redis 服务器响应,从⽽监控运⾏的多个 Redis 实例的运⾏情况;
  3. 当哨兵监测到 Master 宕机,会⾃动将 Slave 切换成 Master,通过通知其他的从服务器,修改配置⽂件切换主机。

3.2 哨兵机制的主要任务

Redis Sentinel 在不使用 Redis 集群时为 Redis 提供高可用性。结合 官方文档 – Redis Sentinel,可以知道 Redis 哨兵具备的能⼒有如下⼏个:

  • 监控:Sentinel 会持续监测 master、slave 是否处于预期工作状态;
  • 自动故障转移:当 Master 运⾏故障,哨兵启动⾃动故障恢复流程:从 slave 中选择⼀台作为新 master;
  • 通知:让 slave 执⾏ replicaof ,与新的 master 同步;并且通知客户端与新 master 建⽴连接;
  • 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

3.2.1 监控

(1)每1s发送一次 PING 命令

哨兵模式启用的时候,会同步启用 sentinel 的进程。sentinel 进程会向所有的 master 和 slaves 以及其他 sentinel进程 发送1s一次 PING 命令(心跳包)。

  • 如果 slave 没有在规定的时间内响应 sentinel 的 PING 命令 , sentinel 会认为该实例已经挂了,将它记录为:「下线状态」;
  • 同理,如果 master 没有在规定时间响应 sentinel 的 PING 命令,也会被判定为 offline 状态,开始执行 「自动切换 master 」 的流程。

(2)PING 命令的回复有两种情况

  • 有效回复:返回 +PONG、-LOADING、-MASTERDOWN 任何一种;
  • 无效回复:有效回复之外的回复,或者指定时间内返回任何回复。

但是还是可能存在因为网络拥塞、master实例假死、请求延迟等导致实例在某个短暂时间段不可用,后续又快速恢复了。如果这时候被我们主动下线了,其实整个系统的可用性反而遭到了退化;而且误判之后的一系列操作,master竞选、消息通知,slave 与新 master 同步数据,都会消耗大量资源。

为了保证判断的可靠性,Redis 对下线的标识做了区分:一种是主观下线,一种是客观下线。

(3)主观下线和客观下线

  • 主观下线

哨兵利用 PING 命令来监测 master、 slave 实例节点的生命状态。如果是无效回复,哨兵就把这个实例节点标记为 「主观下线」。如果是 slave,一般是一主多从,直接下线即可;但如果是 master,就要小心了:一个 sentinel 实例很容易造成误判,那就可以多个 sentinel 实例一起投票判断。

哨兵机制就是这样的,采用多个实例组成 sentinel 集群模式进行部署,即哨兵集群。多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况。

同时,多个哨兵的网络同时不稳定的概率较小,由它们一起做决策,误判率也能降低。

  • 客观下线

master 是否要下线不能是单个 sentinel 实例来决定,上面说了一般会有多个 sentinel 实例(即sentinel集群)。只有当 sentinel 集群里的实例过半判断 master 已经 「主观下线」 了,这时候我们就把 master 标记为 「客观下线」。

当 master 被判定为客观下线后,才会进⼀步触发哨兵执行主从切换流程。

在这里插入图片描述

  • 如何区别主官下线、客观下线

主观下线是 sentinel 实例自己认为节点 offline,这时候节点并不是真正的下线;而客观下线是达到一定数量的 sentinel 实例(比如超过一半)都认为节点 offline 了,这时候会进一步触发离线、重新竞选主等一系列操作。

这里的「一定数量」是一个法定数量(Quorum),是由哨兵监控配置决定的:

# sentinel monitor <master-name> <master-host> <master-port> <quorum>
# 举例如下:
sentinel monitor mymaster 192.168.0.1 6379 2

  • sentinel monitor:代表监控。
  • mymaster:代表主节点的名称,可以自定义。
  • 192.168.0.1:代表监控的主节点 ip,6379 代表端口。
  • 2:法定数量,代表只有两个或两个以上的哨兵认为主节点不可用的时候,才会把 master 设置为客观下线状态,然后进行 failover 操作。

客观下线的标准就是,当有 N 个哨兵实例时,要有 N/2 + 1 个实例判断 master 为 主观下线 ,才能最终判定 master 为 客观下线 ,其实就是过半机制。

3.2.2 主从动态切换

sentinel 的一个很重要工作,就是从多个 slave 中选举出一个新的 master。当然,这个选举的过程会比较严谨,需要通过筛选 + 综合评估方式进行选举。

(1)筛选

  • 过滤掉不健康的(下线或者断线),没有回复哨兵 PING 命令的从节点。
  • 评估实例过往的网络连接状况 down-after-milliseconds,如果一定周期内(如24h)从库和主库经常断连,而且超出了一定的阈值(如 10 次),则该 slave 不予考虑。

这样,就保留下比较健康的实例了。

(2)综合评估

筛选掉不健康的实例之后,我们就可以对于剩下健康的实例按顺序进行综合评估了。

  • slave 优先级:通过 slave-priority 配置项(redis.conf),可以给不同的从库设置不同优先级,优先级高的优先成为 master。
  • 选择数据偏移量差距最小的:即 slave_repl_offset 与 master_repl_offset 进度差距,其实就是比较 slave 与原 master 复制进度差距。
  • slave runID:在优先级和复制进度都相同的情况下,选用 runID 最小的,runID 越小说明创建时间越早,优先选为 master。先来后到原则。

等这几个条件都评估完,我们就会选择出最适合 slave,把他推举为新的 master。

在这里插入图片描述

3.2.3 通知

推选出最新的 master 之后,后续所有的写操作都会进入这个 master 中。所以需要尽快通知到所有的 slave,让他们重新 replacaof 到 master 上,重新建立 runID 和 slave_repl_offset ,来保证数据的正常传输和主从一致性。如下图所示:

在这里插入图片描述

3.3 哨兵机制的工作原理

3.3.1 pub/sub 实现哨兵间通信和发现 slave

集群中的哨兵如何实现通信?

哨兵之间可以相互通信,主要归功于 Redis 的 pub/sub 发布/订阅机制`。哨兵与 master 建立通信之后,可以利用 master 提供发布/订阅机制发布自己的 ip、port 等信息

master 有一个 sentinel:hello 的专用通道,用于哨兵之间发布和订阅消息。哨兵们都可以通过该通道发布自己的 name、ip、port 消息,同时订阅其他哨兵发布的 name、ip、port 消息。互相发现之后建立起了连接,后续的消息通信就可以直接进行了。

这个与微服务中的服务注册与发现,以及RPC通信类似的整套做法类似。

在这里插入图片描述

3.3.2 选择哨兵执⾏主从切换

哨兵如何与 slave 实现连接?

  • sentinel 向 master 发送 INFO 命令
  • master 返回与之关联的 slave 列表
  • sentinel 根据 master 返回的 slave 列表,逐个与 salve 建立连接,并且根据这个连接持续监控

在这里插入图片描述

3.3.3 通过 pub/sub 实现客户端事件通知

哨兵如何与客户端进行事件通知?

通过 pub/sub 机制,发布不同事件,让客户端在这里订阅消息。客户端可以订阅哨兵的消息,哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键事件。

4. 总结

4.1 哨兵主要任务

Redis Sentinel 在不使用 Redis 集群时为 Redis 提供高可用性。主从架构集群的数据同步,是数据可靠性的基础保障;主库宕机,自动执行主从切换是服务不间断的关键支撑。

  • 监控 master 与 slave 运行状态,判断是否客观下线;
  • master 客观下线后,选择一个 slave 切换成 master;
  • 通知 slave 和客户端新 master 信息。

4.2 哨兵集群原理

为了避免单个哨兵故障后无法进行主从切换,以及为了减少误判率,又引入了哨兵集群;哨兵集群又需要有一些机制来支撑它的正常运行:

  • 基于 pub/sub 机制实现哨兵集群之间的通信;
  • 基于 INFO 命令获取 slave 列表,帮助哨兵与 slave 建立连接;
  • 通过哨兵的 pub/sub,实现了与客户端和哨兵之间的事件通知。
  • 主从切换,并不是随意选择一个哨兵就可以执行,而是通过投票选举,选择一个 master,由这个 master 负责主从切换。

Redis 6.X Sentinel 哨兵集群搭建