你真的懂 Redis 哨兵集群吗?一主二从三哨兵架构如何扛住百万级并发?

数据库 Redis
主从复制架构面临一个严峻问题:master 宕机,无法执行写操作,无法自动选择将一个 slave 切换为 master,也就是无法实现自动故障切换。

通过之前的学习,你已知道 Redis 主从复制是高可用的基石,某个 slave 宕机依然可以将请求发送给 master 或者其他 slave,但是如果 master 宕机,则只能响应读操作,写请求无法再执行。

所以主从复制架构面临一个严峻问题:master 宕机,无法执行写操作,无法自动选择将一个 slave 切换为 master,也就是无法实现自动故障切换。

Chaya:“还记得那晚我与男友约会,眼前是橡树的绿叶,白色的竹篱笆。好想告诉我的他,这里像幅画,一起手牵手么么哒(此处省略 10000 字)。

“Redis 忽然宕机,我的恋人小 Q 总不能把我推开,停止甜蜜,然后打开电脑手工进行主从切换,再通知其他程序员把地址改成新 master 的信息上线。”

如此一折腾,你心里的雨倾盆地下,万万使不得。所以必须有一个高可用的方案,为此,我提供一个高可用方案——哨兵(sentinel)。

哨兵是什么?

吃瓜群众:“Redis 大佬,虽然我没有女朋友,但是未雨绸缪,我要掌握这个哨兵模式,防止当我与女朋友约会时被打扰,你快说说什么是哨兵以及哨兵的实现原理吧。”

先来看看哨兵是什么?搭建哨兵集群的方法我就不细说了,假设三个哨兵组成一个哨兵集群,三个数据节点构成一个一主两从的 Redis 主从架构,如图 3-17 所示。

图3-17

Redis 哨兵集群高可用架构有三种角色,分别是 master、slave 和 sentinel。

  • sentinel 之间互相通信,组成一个集群实现哨兵高可用,选举出一个 leader 执行故障迁移操作。
  • master 与 slave 之间通信,组成主从复制架构。
  • sentinel 与 master/ slave 通信,是为了对该主从复制架构进行管理,包括监视(Monitoring)、通知(Notification)、自动故障切换(Automatic Failover)、配置提供者(Configuration Provider)。

哨兵监控的 master 的名字叫作 mymaster,master 的 IP 地址是 127.0.0.1,端口是 6379。quorum 是关键参数,它的作用如下。

  • 指定在标记 master 故障并尝试执行故障切换时需要一定数量达成一致意见的哨兵进程。大白话就是需要多少个哨兵进程认为 master 宕机,真正标记 master 宕机才能启动故障切换过程。
  • 对于多个哨兵,需要选出一个 leader 来执行实际的故障自动转移操作,当某个哨兵的票数超过 quorum 时,就选举这个哨兵为 leader,负责自动故障切换。quorum 的值一般取哨兵个数的一半以上 (n/2 + 1) 比较合理。

哨兵只要配置 master 信息即可与三个角色建立联系。

Chaya:“为什么哨兵只需要配置 master 信息就可以与三个角色建立联系?”

  • 哨兵可以通过 master 获取 slave 的信息,并与 slave 建立连接。master 与 slave 是主从关系,通过 info 命令就可以通过 master 获取 slave 的 IP 地址 和 port、runid 等信息。
  • 通过上面的步骤,哨兵与 master 和所有的 slave 建立连接,哨兵之间的互相感知则通过 Redis 的发布/订阅机制实现。每个哨兵通过发布/订阅 master 的 sentinel:hello 频道发布和接收信息,以此感知其他哨兵的存在并建立连接。

哨兵的任务

哨兵是 Redis 的一种运行模式,它专注于对 Redis 实例(master、slave)运行状态的监控,并能够在 master 发生故障时通过一系列的机制实现选主及主从切换,实现自动故障切换,确保整个 Redis 系统的可用性。

Chaya 可以安心地与爱人在欢乐港湾约会,尽情享受甜蜜,哪怕是吵架都那么醉人,不再需要担心 Redis 忽然宕机带来的烦恼。

我们先从全局看哨兵,简要地了解它的整个运作流程,接着针对每个任务详细分析,Redis 哨兵的主要职责如下。

  • 监控(Monitoring):Redis 的哨兵不断检查 master 和 slave 实例是否按预期工作。它监视实例的健康状态,包括 master 和所有 slave。
  • 自动故障切换(Automatic Failover)**:如果 master 出现故障或不按预期工作,Redis 的哨兵则启动自动故障切换流程。在此过程中,一个 slave 会被晋升为新的 master。
  • 通知(Notification):让 slave 执行 replicaof 命令与新的 master 同步数据;并且通知客户端与新的 master 建立连接,如图 3-18 所示。
  • 配置提供者(Configuration Provide):哨兵充当了客户端服务发现的权威来源。客户端连接到任何一个哨兵以获取新的 master 的地址,确保能够连接到正确的实例。

1. 监控

Redis :八卦一下,Chaya,你的恋人用什么方式来了解你每天的喜怒哀乐呢?

Chaya:“这很简单,他每天给我发微信消息、打电话或者打视频,若是哪天我不接电话,或者他发送微信消息时出现红色感叹号,就说明我把他拉黑了。”

哨兵与各个角色节点建立连接后,通过PING、INFO、PUBLISH / SUBSCRIBE命令来监控所有实例的健康状态,当然,它不会说情话。

哨兵默认会以每秒一次的频率向所有的 master、slave、哨兵发送 PING 命令,这个其实是一个心跳检测,用于探测实例是否存活。

  • PING:所有节点之间通过发送 PING 命令确认对方是否在线,默认每秒发送一次。
  • I NFO:哨兵向 master、slave 发送该命令,用于获取 slave 的详细信息。
  • PUBLISH / SUBSCRIBE:哨兵会订阅 master 和 slave 的 sentinel:hello 频道,并通过该频道发布自己的信息,这样其他哨兵之间就可以建立联系。

如果一个 master 实例距离最后一次有效回复 PING 命令的时间超过 down-after- milliseconds 选项所指定的值,这个 master 实例就会被哨兵标记为“主观下线”。

如果 slave 没有在指定时间内响应哨兵的 PING 命令,则直接被标记为“主观下线”。

只有当大于或等于法定个数(quorum)的哨兵节点认为该 master 主观下线时,才能将该 master 改为客观下线。接着才会开启自动故障切换流程。

PING 命令的回复有两种情况。

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

Chaya:“主观下线和客观下线的作用是什么?”

主要是为了避免出现哨兵误判 master 运行的情况,一旦出现误判,就会出现 master 实际没有下线,可是哨兵误以为其已经下线的情况,接着就会启动主从故障切换流程,之后的选主和通知操作都会消耗大量资源。

误判一般会发生在集群网络压力较大、网络拥塞或者是 master 本身压力较大的情况下。

既然一个哨兵容易误判,那就使用多个哨兵进行投票判断。哨兵机制也是类似的,采用多实例组成的集群模式进行部署,就是哨兵集群。

引入多个哨兵实例一起进行判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况。

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

主观下线

主观下线(Subjectively Down,SDOWN)指一个哨兵认为一个 Redis 实例已经不可用或者已经下线,这有可能是网络不通、心跳超时或连接失败等原因导致的。

例如对于 master 或者 slave,在 down-after-milliseconds 指定的毫秒数之内,如果没有向哨兵发送的 PING 命令回复,或者返回一个错误,那么哨兵会将这个服务器标记为主观下线。

需要注意的是,Redis 的哨兵的主要目标是确保 master 的高可用性,而不是 slave 的高可用性。

因此,主观下线和客观下线的主要关注点通常是 master。slave 通常不会被单独标记为客观下线,因为它们不承担 master 的关键角色,它们的主要责任是复制数据。

客观下线

判断 master 是否下线不能只由一个哨兵说了算,只有过半的哨兵判断 master 主观下线,才能将 master 标记为客观下线,如图 3-19 所示。

3-19

之前提到过 sentinel monitor <master-name> <ip> <redis-port> <quorum> 的配置,参数 quorum 是判断客观下线的依据之一,意思是至少有 quorum 个哨兵判定这个 master 主观下线,才会将这个 master 标记为客观下线。

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

2. 自动故障切换

Chaya:“一旦判断 master 客观下线,就在 slave 中选一个作为新的 master 吗?”

哨兵的第二个任务是选择一个 slave 作为新的 master,并对外提供服务。之后其他 slave 会与新的 master 进行主从复制,这个过程叫作自动故障切换,如图 3-20 所示。

3-20

吃瓜群众:“如何从众多 slave 中选出一个做 master 呢?”

Chaya:“我觉得筛选过程就像找恋爱对象,每个人心中都有标尺,会通过直觉、习惯和自己的标准从所有的追求者中选择一个最适合自己的。”

类似地,Redis 有自己的筛选规则,按照一定的筛选条件和打分策略,选出一个“节点”担任 master。

筛选条件

Chaya:“有哪些筛选条件?”

  • 下线或网络断连的 slave 直接丢弃。
  • 网络无异常:slave 最后一次响应 PING 命令的时间不能超过 5 倍 PING 周期;slave INFO(每 10s 发送一次 INFO 命令)的信息更新时间不能超过 3 倍 INFO 刷新周期。
  • 评估过往的网络状态:slave 与 master 断开连接,断连时间不能超过(现在-master 被标记为下线的时间)+(master 的 down-after- milliseconds 配置项的值乘以 10),单位是毫秒。

总之,下线或者网络经常断开的 slave 不能要。如果新的 master 很快出现网络故障,就又得重新选择新的 master,这不“闹着玩”吗,得排除掉!

打分

过滤掉不合适的 slave 之后,使用快速排序对 slave 列表进行打分,按照以下排序找出“王者”。

  • slave 优先级:通过 replica-priority 100 配置项,给不同的 slave 配置不同优先级,默认是 100,值越低,优先级越高,配置为特殊值 0 表示不会晋升为 master。
  • 更大复制偏移量(processed replication offset):已复制的数据量越多,slave_repl_offset 与 master_repl_offset 的差值就越小。
  • slave runID:在优先级和复制进度都相同的情况下,runID 最小的 slave 得分最高,该 slave 会被选为新的 master。

哨兵向筛选出来的 slave 发送 slave no one 命令,使得该 slave 成为新的 master,哨兵并不关心命令返回的结果,它会发送 info 命令给 slave,并根据命令的回复内容确认 slave 是否成功转换为 master。

Chaya:“旧的 master 重新恢复正常时要怎么处理?”

旧的不去,新的不来,有些人一旦错过就不在,既然已经错过,相逢也只能是过客。

原 master 恢复正常,重新连接哨兵,这时集群已经有新的 master,所以旧的 master 被哨兵降级为 slave。

3. 通知

新的 master 出现后,哨兵还有一件重要的事情要做——将新的 master 的连接信息通过 slave 命令发送给其他 slave,通知 slave 执行 replacaof 命令和新的 master 建立连接进行主从复制。

接着,哨兵会定时给 slave 发 INFO 命令,从 INFO 命令的回复内容来确认 slave 是否与新的 master 成功建立连接。检测到所有 slave 都与新的 master 建立连接,自动故障切换就完成了。

如果还有剩余 slave 没有连上新的 master,则哨兵还会再做一次努力,再次向这些 slave 发送 slave 命令,要求他们与新的 master 建立连接。

4. 配置提供者

Redis 客户端只需要跟哨兵打交道,就可以无感知地连接到新的 master,最重要的原因是哨兵提供了一些 API 来检查主从节点的运行状况。

哨兵集群实现原理

如果只有一个哨兵就会存在单点故障问题。Redis sentinel 是一个分布式系统,由多个哨兵协作组成集群实现高可用。

  • 当多个哨兵达成一致认为某个 master 不可用时,才执行故障迁移,降低了误报的概率。
  • 不需要所有哨兵都可用,哨兵集群依然可以正常工作。

Chaya:“哨兵是如何感知其他哨兵节点的呢?又如何知道 slave 节点的信息并监控呢?当 master 不可用时,到底由哪个哨兵来执行自动故障切换呢?”

1. 发布/订阅机制

哨兵互相发现

哨兵之间可以互相感知发现,这归功于 Redis 的发布/订阅机制。

当哨兵与 master 建立连接后,使用发布/订阅机制在特殊的频道发布自己的信息,例如 IP 地址和端口,同时订阅该频道获取其他哨兵发布的消息。

master 有一个 sentinel:hello 的专用通道,用于哨兵之间发布和订阅消息。

可以比喻为哨兵利用 master 建立的sentinel:hello 微信群发布自己的消息,同时关注其他哨兵发布的消息,如图 3-21 所示。

3-21

哨兵如何感知并监控 slave

哨兵之间建立连接形成集群还不够,哨兵还需要跟所有 slave 建立连接,否则无法监控它们。除此之外,如果发生了主从切换也需要通知 slave 重新与新的 master 建立连接进行数据同步。

哨兵向 master 发送 INFO 命令,master 接收到命令后,将 slave 列表告诉哨兵。

哨兵根据 master 响应的 slave 名单信息与所有 salve 建立连接,并且根据这个连接持续监控 slave,剩下的哨兵也基于此实现监控,如图 3-22 示。

2. 选择哨兵执行主从切换

Chaya:“master 不可用后,如何选择一个哨兵来执行自动故障切换呢?”

任何哨兵判断 master 主观下线后,都会向其他哨兵发送 is-master-down-by- addr 命令,其他哨兵收到命令后则根据自己与 master 之间的连接状况分别响应 Y 或者 N,Y 表示赞成,N 表示反对。

如果某个哨兵获得了大多数哨兵的赞成票,就标记 master 为客观下线。

例如,一共有 3 个哨兵组成集群,那么 quorum 就可以配置为 2,当一个哨兵获得了 2 张赞成票(包含自己的 1 票)时,就可以标记 master“客观下线”。

获得多数赞成票的哨兵向其他哨兵发送 SENTINEL is-master-down-by-addr <masterip> <masterport> <sentinel.current_epoch>命令,声明自己想要执行主从切换并开始拉票。

其他哨兵则进行投票,投票过程叫作 leader 选举,选举的过程借鉴了分布式系统中的 Raft 协议。

简单地说,哨兵标记当前 master 客观下线后,通过投票的方式从哨兵集群中选举出一个哨兵作为 leader 角色执行故障切换。

Chaya:“我发现判断 master 是否客观下线和哨兵拉票选举 leader 是同样的命令。”

没错,is-master-down-by-addr 命令有两个作用:

  • 一是询问其他哨兵是否认为某个 master 已经主观下线;
  • 二是开始进行自动故障切换时,当前哨兵向其他哨兵实例进行"拉票",让其他哨兵选举自己为 leader。

哨兵想要成为 leader 没那么简单,得有两把“刷子”。需要满足以下条件。

  • 获得其他哨兵过半的投票。
  • 投票的数量大于或等于 quorum 的值。

如果 sentine 集群有 2 个实例,此时,一个哨兵要想成为 leader,那么必须获得 2 票,而不是 1 票。

所以,如果有一个哨兵宕机了,那么此时的集群是无法进行主从库切换的。因此,通常我们至少会配置 3 个哨兵实例。

3. 发布/订阅机制

在 Redis 中,发布/订阅(Pub/Sub)机制发布不同事件,让客户端订阅消息。哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键事件。

master 相关

与 master 相关的消息订阅频道。

◎ +sdown:节点处于主观下线状态。

◎ -sdown:节点不再处于主观下线状态。

◎ +odown:节点进入客观下线状态。

◎ -odown:节点退出客观下线状态。

◎ +switch-master:master 地址发生了变化。

slave 相关

与 slave 相关的消息订阅频道。

◎ +slave-reconf-sent:leader 哨兵发送 REPLICAOF 命令重新配置从库。

◎ +slave-reconf-inprog:slave 配置了新的 master,但是尚未同步。

◎ +slave-reconf-done:slave 配置了新的 master,并完成了数据同步。

Redis 的发布/订阅机制尤其重要,有了发布/订阅机制,哨兵和哨兵之间、哨兵和 slave 之间、哨兵和客户端之间就都能建立起连接了,各种事件的发布也是通过这个机制实现的。

责任编辑:姜华 来源: 码哥跳动
相关推荐

2025-01-12 13:06:45

2023-04-11 08:30:52

2023-10-26 07:47:53

Redis哨兵集群

2023-09-27 06:26:07

2022-06-08 16:55:56

服务器Redis架构

2022-12-21 09:50:41

2021-04-01 08:50:54

SentinelRedis 集群原理

2022-02-14 08:33:51

Redis哨兵集群

2020-04-14 21:12:42

Redis集群Linux

2019-05-13 14:17:06

抓包Web安全漏洞

2021-03-31 05:57:40

集群搭建哨兵集群Redis

2022-02-11 08:41:19

WindowsRedis集群

2025-02-14 03:00:00

2020-06-08 08:20:11

Redis高可用集群

2024-07-16 08:38:06

2019-10-18 09:50:47

网络分层模型网络协议

2019-09-03 15:45:31

Redis分片集群

2019-09-15 10:38:28

网络分层模型

2023-11-29 08:03:05

2020-09-02 17:28:26

Spring Boot Redis集成
点赞
收藏

51CTO技术栈公众号