哨兵机制原理详解

这篇具有很好参考价值的文章主要介绍了哨兵机制原理详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

初始化 Sentinel

初始化 Sentinel 的最后一步是创建连向 master 的网络连接,Sentinel将成为 master 的客户端,它可以向主服务器发送命令,并从命令回复中获取相关的信息。
对于每个被 Sentinel 监视的主服务器来说,Sentinel 会创建两个连向主服务器的异步网络连接:

  1. 命令连接:这个连接专门用于向主服务器发送命令,并接收命令回复。
  2. 订阅连接:这个连接专门用于订阅主服务器的 __sentinel__ :hello 频道。

为什么要建立两个连接:

在Redis目前的发布与订阅功能中,被发送的信息都不会保存在Redis服务器里面,如果在信息发送时,想要接收信息的客户端不在线或者断线,那么这个客户端就会丢失这条信息。因此,为了不丢失__sentinel__:hello频道的任何信息,Sentinel必须专门用一个订阅连接来接收该频道的信息。

另一方面,除了订阅频道之外,Sentinel还必须向主服务器发送命令,以此来与主服务器进行通信,所以Sentinel还必须向主服务器创建命令连接。

因为Sentinel需要与多个实例创建多个网络连接,所以Sentinel使用的是异步连接。

三个定时任务(重要)

Sentinel 维护着三个定时任务以监测 Redis 节点及其它 Sentinel 节点的状态。

INFO任务

在 Sentinel 的配置文件中有 master 的IP和端口号,所以 Sentinel 在初始时是知道 master 节点的位置,于是 Sentinel 可以向 master 建立命令连接和订阅连接。

Sentinel默认会以每十秒一次的频率,通过命令连接向 master 发送 INFO 命令,并通过分析 master 返回的 INFO 命令回复更新主从节点的相关信息。下面是INFO命令的回复的例子:

# Server
...
run_id:7611c59dc3a29aa6fa0609f841bb6a1019008a9c
...
# Replication
role:master
...
slave0:ip=127.0.0.1,port=11111,state=online,offset=43,lag=0
slave1:ip=127.0.0.1,port=22222,state=online,offset=43,lag=0
slave2:ip=127.0.0.1,port=33333,state=online,offset=43,lag=0
...
# Other sections
...

Sentinel 可以获取以下两方面的信息:

  1. 一方面是关于 master 本身的信息,包括master的运行ID(run_id:7611c59······a9c),以及master的角色(role:master)。
  2. 另一方面是关于master属下所有slave的信息,每个slave都由一个"slave"字符串开头的行记录,每行的ip域记录了slave的IP地址,而port域则记录了slave的端口号。根据这些IP地址和端口号,Sentinel无须用户提供slave的地址信息,就可以自动发现slave。

当 Sentinel 发现slave的IP和端口号之后就可以向slave发起命令连接和订阅连接,从而获得slave更加具体的信息。Sentinel向slave发送INFO命令,会得到类似如下的回复:

# Server
...
run_id:32be0699dd27b410f7c90dada3a6fab17f97899f
...
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
slave_repl_offset:11887
slave_priority:100
# Other sections
...

根据INFO命令的回复,Sentinel会提取出以下信息:

  1. slave的运行ID(run_id)。
  2. slave的角色role。
  3. master的IP地址master_host,以及master的端口号master_port。
  4. master的连接状态master_link_status。
  5. slave的优先级slave_priority。
  6. slave的复制偏移量slave_repl_offset。

根据这些信息,Sentinel会对slave的相关信息进行更新。

总结:
Sentinel 每隔10s就会通过命令连接向所有的master和slave节点发送INFO命令,根据命令的回复,sentinel可以知道master和slave的各种详细信息,并更新相关数据。

订阅/发布任务

当Sentinel与一个master或者slave建立起订阅连接之后,Sentinel就会通过订阅连接,向服务器发送以下命令:

SUBSCRIBE __sentinel__:hello

Sentinel对 __sentinel__:hello 频道的订阅会一直持续到Sentinel与Redis节点的连接断开为止。 订阅成功后,每个 Sentinel 节点每 2 秒就会向每个 Redis 节点发布一条__sentinel__ :hello 主题的信息(通过命令连接发送publish命令),当 Redis 节点中该主题的信息发生了变化,就会立即通知到所有订阅者(Sentinel)。举个例子,假设现在有sentinel1、sentinel2、sentinel3三个Sentinel在监视同一个master,那么当sentinel1向master的 __sentinel__ :hello 频道发送一条信息时,所有订阅了 __sentinel__ :hello 频道的Sentinel(包括sentinel1自己在内)都会收到master的返回信息。

当一个Sentinel从 __sentinel__:hello 频道收到一条信息时,Sentinel会对这条信息进行分析,提取出信息中的Sentinel IP地址、Sentinel端口号、Sentinel运行ID等八个参数(通过这些信息,当前的Sentinel就可以知道其他Sentinel的IP和端口号,从而向其他Sentinel建立连接),并进行以下检查:

  • 如果本地信息中记录的Sentinel运行ID和接收信息的Sentinel的运行ID相同,那么说明这条信息是Sentinel自己发送的,Sentinel将丢弃这条信息,不做进一步处理。
  • 如果本地信息中记录的Sentinel运行ID和接收信息的Sentinel的运行ID不相同,那么说明这条信息是监视同一个Redis节点的其他Sentinel发来的,接收信息的Sentinel将根据信息中的各个参数,对相应master节点的相关信息进行更新(Sentinel节点本地存储了master节点的相关信息,对这里面的信息进行更新)。
  • 如果接收信息的Sentinel的运行ID在本地中不存在,那么说明有新建立的Sentinel节点对master节点的监控,当前Sentinel节点会在master的记录中增加一条新Sentinel节点的信息。

当Sentinel通过频道信息发现一个新的Sentinel时,它不仅会为新Sentinel创建相关记录信息,还会创建一个连向新Sentinel的命令连接,而新Sentinel也同样会创建连向这个Sentinel的命令连接,最终监视同一master的多个Sentinel将形成相互连接的网络。

Sentinel之间不会创建订阅连接
Sentinel在连接master或者slave时,会同时创建命令连接和订阅连接,但是在连接其他Sentinel时,却只会创建命令连接,而不创建订阅连接。这是因为Sentinel需要通过接收master或者slave发来的频道信息来发现未知的新Sentinel,所以才需要建立订阅连接,而相互已知的Sentinel只要使用命令连接来进行通信就足够了。

总结:

每个 Sentinel 节点每 2 秒就会向每个 Redis 节点发布一条消息。因为一个Sentinel可以通过分析接收到的频道信息来获知其他Sentinel的存在,并通过发送频道信息来让其他Sentinel知道自己的存在,所以用户在使用Sentinel的时候并不需要提供各个Sentinel的地址信息,监视同一个master的多个Sentinel可以自动发现对方。

心跳任务

在默认情况下,Sentinel会以每秒一次的频率向所有与它创建了命令连接的节点(包括master、slave、其他Sentinel在内)发送PING命令,并通过节点返回的PING命令回复来判断节点是否在线。

节点对PING命令的回复可以分为以下两种情况:

  1. 有效回复:实例返回+PONG、-LOADING、-MASTERDOWN三种回复的其中一种。
  2. 无效回复:实例返回除+PONG、-LOADING、-MASTERDOWN三种回复之外的其他回复,或者在指定时限内没有返回任何回复。

Redis节点下线判断

主观下线判断

Sentinel配置文件中的down-after-milliseconds选项指定了Sentinel判断Redis节点进入主观下线所需的时间长度:如果一个节点在down-after-milliseconds毫秒内,连续向Sentinel返回无效回复,那么Sentinel会修改这个节点的相关消息,把该节点的flags属性增加SRI_S_DOWN标识,以此来表示这个实例已经进入主观下线状态。

用户设置的down-after-milliseconds选项的值,不仅会被Sentinel用来判断master的主观下线状态,还会被用于判断master属下的所有slave,以及所有同样监视这个master的其他Sentinel的主观下线状态。举个例子,如果用户向Sentinel设置了以下配置:

sentinel monitor mymaster 127.0.0.1 6380 2
sentinel down-after-milliseconds mymaster 30000

那么30000毫秒会成为Sentinel判断master、master属下所有slave、监视该master的其他Sentinel进入主观下线的标准。

注意:在Redis的分布式集群中,多个Sentinel设置的主观下线时长可能不同。这样可能会造成Sentinel1认为master主观下线,而Sentinel2并不认为master主观下线的情况。

客观下线判断

当Sentinel将一个master判断为主观下线之后,为了确认这个master是否真的下线了,它会向同样监视这一master的其他Sentinel进行询问,看它们是否也认为master已经进入了下线状态(可以是主观下线或者客观下线)。当Sentinel从其他Sentinel那里接收到足够数量(数量大于等于 quorum )的已下线判断之后,Sentinel会将master的flags属性增加SRI_O_DOWN标识,表示master已经进入客观下线状态,并对master执行故障转移操作。

Sentinel Leader 选举

当 Sentinel 节点对 master 做出客观下线判断后会由 Sentinel Leader 来完成后续的故障转移,即 Sentinel 集群中的节点也并非是对等节点,是存在 Leader 与 Follower 的。

Sentinel 集群的 Leader 选举是通过 Raft 算法实现的。Raft 算法比较复杂,详见:Raft算法详解 - 知乎 。这里仅简单介绍一下大致思路。

每个选举参与者都具有当选 Leader 的资格,当其完成了“客观下线”判断后,就会立即“毛遂自荐”推选自己做 Leader,然后将自己的提案发送给所有参与者。其它参与者在收到提案后,只要自己手中的选票没有投出去,其就会立即通过该提案并将同意结果反馈给提案者,后续再过来的提案会由于该参与者没有了选票而被拒绝。当提案者收到了同意反馈数量大于等于 max(quorum,sentinelNum/2+1)时,该提案者当选 Leader。

说明:

  • 在网络没有问题的前提下,基本就是谁先做出了“客观下线”判断,谁就会首先发起Sentinel Leader 的选举,谁就会得到大多数参与者的支持,谁就会当选 Leader。

  • Sentinel Leader 选举会在次故障转移发生之前进行。

  • 故障转移结束后 Sentinel 不再维护这种 Leader-Follower 关系,即 Leader 不再存在。

故障转移过程

整体过程

在选举产生出Sentinel Leader之后,Sentinel Leader 将对已下线的master执行故障转移操作,该操作包含以下三个步骤:

  1. 在已下线master属下的所有slave里面,挑选出一个slave,并将其角色转换为master。
  2. 让已下线master属下的所有slave改为复制新的master。
  3. 将已下线的master设置为新master的slave,当这个旧的master重新上线(重启)时,它就会成为新master节点的slave。

故障转移操作第一步要做的就是在已下线的master属下的所有slave中,挑选出一个状态良好、数据完整的slave,然后向这个slave发送SLAVEOF no one命令,将这个slave转换为master。

Master 选择算法

在进行故障转移时,Sentinel Leader 需要从所有 Redis 的 Slave 节点中选择出新的 Master。其选择算法为:

  1. 删除列表中所有处于下线或者断线状态的从服务器,这可以保证列表中剩余的从服务器都是正常在线的。
  2. 删除列表中所有最近五秒内没有回复过Sentinel Leader的INFO命令的从服务器,这可以保证列表中剩余的从服务器都是最近成功进行过通信的。
  3. 删除所有与已下线master连接断开超过down-after-milliseconds*10毫秒的slave:down-after-milliseconds选项指定了判断主服务器下线所需的时间,而删除断开时长超过down-after-milliseconds*10 毫秒的从服务器,则可以保证列表中剩余的从服务器都没有过早地与主服务器断开连接,换句话说,列表中剩余的从服务器保存的数据都是比较新的。
  4. 删除replica-priority(优先级)值为 0 的 Redis节点。
  5. 在剩余 Redis 节点中选择出 replica-priority 最小的的节点列表。如果只有一个节点,则直接返回,否则,继续。
  6. 从优先级相同的节点列表中选择复制偏移量最大的节点(和已宕机的master节点的相似度最高)。如果只有一个节点,则直接返回,否则,继续。
  7. 从复制偏移值量相同的节点列表中选择动态 ID 最小的节点返回。

对最后选择的slave发送SLAVEOF no one命令之后,Sentinel Leader会以每秒一次的频率(平时是每十秒一次),向被升级的从服务器发送INFO命令,并观察命令回复中的角色(role)信息,当被升级服务器的role从原来的slave变为master时,Sentinel Leader就知道被选中的从服务器已经顺利升级为master了。

修改从服务器的复制目标

当新的主服务器出现之后,Sentinel Leader下一步要做的就是,让已下线master属下的所有slave去复制新的master,这一动作可以通过向slave发送SLAVEOF命令来实现。

将旧的主服务器变为从服务器

故障转移操作最后要做的是,将已下线的master设置为新的master的slave。因为旧的master已经下线,所以这种设置是保存在旧master的记录信息中,当旧master重新上线时,Sentinel (不是Sentinel Leader)就会向它发送SLAVEOF命令,让它成为新master的slave。

节点上线

原Redis节点上线

无论是原下线的 master 节点还是原下线的 slave 节点,只要是原 Redis 集群中的节点上线,只需启动 Redis 即可。因为每个 Sentinel 中都保存有原来其监控的所有 Redis 节点列表,Sentinel 会定时查看这些 Redis 节点是否恢复。如果查看到其已经恢复,则会命其从当前master 进行数据同步。不过,如果是原 master 上线,在新 master 晋升后 Sentinel Leader 会立即先将原 master 节点更新为 slave,并同步新master节点的数据。

新Redis节点上线

如果需要在 Redis 集群中添加一个新的节点,其未曾出现在 Redis 集群中,则上线操作只能手工完成。即添加者在添加之前必须知道当前 master 是谁,然后在新节点启动后运行slaveof 命令加入集群。

Sentinel节点上线

如果要添加的是 Sentinel 节点,无论其是否曾经出现在 Sentinel 集群中,都需要手工完成。即添加者在添加之前必须知道当前 master 是谁,然后在配置文件中修改 sentinel monitor属性,指定要监控的 master。然后启动 Sentinel 即可。文章来源地址https://www.toymoban.com/news/detail-458184.html

到了这里,关于哨兵机制原理详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • redis夯实之路-哨兵(Sentinel)机制详解

    Sentinel(哨兵)保证了redis的高可用性,一个Sentinel或多个Sentinel组成的系统监视多个主从服务器,当主服务器下线时,自动将一个从服务器升级为主服务器。 集群监控:负责监控redis master和slave进程是否正常工作  消息通知:如果某个redis实例有故障,那么哨兵负责发送消息给

    2024年01月21日
    浏览(32)
  • C语言字符串初始化详解:用常量字符串进行字符数组初始化

    简介 字符串初始化 用常量字符串 初始化过程 示范代码 结论 在C语言中,字符串被定义为字符数组。字符串的初始化是指将一个常量字符串复制到字符数组中。本文将详细介绍字符串的初始化方法,并提供相应的示范代码。 在C语言中,有几种常用的方法可以用常量字符串来

    2024年02月15日
    浏览(37)
  • SpringBoot 底层机制分析【Tomcat 启动+Spring 容器初始化+Tomcat 如何关联Spring 容器】【下】

    😀前言 本篇博文是关于SpringBoot 底层机制分析实现,希望能够帮助你更好的了解SpringBoot 😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客

    2024年02月13日
    浏览(34)
  • Docker 制作 MySQL 镜像并使用 `/docker-entrypoint-initdb.d/` 机制初始化数据

    制作一个 MySQL Docker 镜像并初始化数据库信息 win 11 Docker-Desktop 4.14.0 (91374) 启动一个MySQL容器很容易。如何初始化数据呢? 大概我们会尝试很多操作,比如百度常见到 使用 CMD 命令调用shell脚本,通过shell脚本处理初始化数据等等,经过实践,这些都不太方便。 其实,MySQL 官方提

    2024年01月18日
    浏览(39)
  • 路由器配置与初始化详解

    路由器的配置方式与交换机基本相同。除了都可以采用图形化界面配置以外,也都支持使用CLI命令行进行配置。由于交换机与路由器的许多CLI配置命令完全相同,因此,两者之间的配置差异并不大。 1、路由器配置前规划 对于局域网而言,路由器往往就是指边缘路由器,即用

    2024年01月21日
    浏览(34)
  • Redis高可用:哨兵机制(Redis Sentinel)详解

    目录 1.什么是哨兵机制(Redis Sentinel) 2.哨兵机制基本流程 3.哨兵获取主从服务器信息 4.多个哨兵进行通信 5.主观下线和客观下线 6.哨兵集群的选举 7.新主库的选出 8.故障的转移 9.基于pub/sub机制的客户端事件通知 Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心

    2024年02月12日
    浏览(29)
  • Spring Boot 系统初始化器详解

    Spring Boot 3.x系列文章 Spring Boot 2.7.8 中文参考指南(一) Spring Boot 2.7.8 中文参考指南(二)-Web Spring Boot 源码阅读初始化环境搭建 Spring Boot 框架整体启动流程详解 Spring Boot 系统初始化器详解 Spring Boot 有多种加载自定义初始化器的方法: 1、创建一个实现ApplicationContextInitializer接口的

    2024年02月11日
    浏览(39)
  • 消失的死锁:从 JSF 线程池满到 JVM 初始化原理剖析

    在一次上线时,按照正常流程上线后,观察了线上报文、接口可用率十分钟以上,未出现异常情况,结果在上线一小时后突然收到jsf线程池耗尽的报警,并且该应用一共有30台机器,只有一台机器出现该问题,迅速下线该机器的jsf接口,恢复线上。然后开始排查问题。 [WARN]

    2024年02月08日
    浏览(30)
  • 一文详解 springboot 项目启动时异步执行初始化逻辑

    你知道的越多,你不知道的越多 点赞再看,养成习惯 如果您有疑问或者见解,欢迎指教: 企鹅:869192208 前言 前面的工作中,为了提高地区数据的响应时间,需要加载全国区划数据到 redis 中缓存起来,这个过程希望在项目时启动。 由于初始化全国区划到 redis 中这个过程是

    2024年02月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包