【Redis-07】Redis哨兵机制Sentinel的实现原理

news2024/10/6 10:34:27

 Sentinel是Redis高可用性的解决方案:由一个或者多个Sentinel实例组成的哨兵系统监视多个主从服务器,并实现主从服务器的故障转义。
 Sentinel本质上只是一个运行在特殊模式下的Redis服务器,使用以下命令可以启动并初始化一个Sentinel实例:

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

 下面我们看一下,启动一个Sentinel实例后,它做了哪些初始化步骤吧。

1. 启动并初始化Sentinel

1.1 初始化服务器

 因为Sentinel也是一台Redis服务器,所以启动后的第一步就是初始化服务器,但是这里的初始化和之前我们普通的Redis服务器不太一样,有些步骤不需要执行,例如载入持久化文件还原数据库状态等等。

1.2 使用Sentinel专用代码

 初始化后的第二步就是将一部分Redis服务器的代码替换成为Sentinel的专用代码,比如服务器的默认端口号,比如Sentinel模式下的命令表等等,正是由于两者使用的命令表不同,所以在哨兵模式下,有些普通键值对命令无法正常执行。

1.3 初始化Sentinel的状态

 接下来Sentinel服务器会初始化一个SentinelState的结构,这里面用于保存和哨兵模式相关的一些状态属性。源代码如下,先混个眼熟,下面我们讲解各部分过能时会用到里面的属性。

struct sentinelState {
	// 当前sentinel的运行id
    char myid[CONFIG_RUN_ID_SIZE+1]; /* This sentinel ID. */
    // 当前纪元
    uint64_t current_epoch;         /* Current epoch. */
    // 所监视的主服务器字典
    dict *masters;      /* Dictionary of master sentinelRedisInstances.
                           Key is the instance name, value is the
                           sentinelRedisInstance structure pointer. */
    int tilt;           /* Are we in TILT mode? */
    int running_scripts;    /* Number of scripts in execution right now. */
    mstime_t tilt_start_time;       /* When TITL started. */
    mstime_t previous_time;         /* Last time we ran the time handler. */
    list *scripts_queue;            /* Queue of user scripts to execute. */
    char *announce_ip;  /* IP addr that is gossiped to other sentinels if
                           not NULL. */
    int announce_port;  /* Port that is gossiped to other sentinels if
                           non zero. */
    unsigned long simfailure_flags; /* Failures simulation. */
    int deny_scripts_reconfig; /* Allow SENTINEL SET ... to change script
                                  paths at runtime? */
} sentinel;

1.4 初始化sentinelState的masters属性

 这个masters属性是一个指针,指向一个dict结构,记录了所有被Sentinel监视的主服务器的信息,记住,这里是主服务器。其中key = 主服务器的名字,value = 主服务器的实例结构(由sentinelRedisInstance结构实现)
 这里提到了**sentinelRedisInstance结构,它可以是主服务器,从服务器或者另一个Sentinel实例。这里仅展示一部分代码片段:

typedef struct sentinelRedisInstance {
    // 该实例当前的状态
    int flags;      /* See SRI_... defines */
    // 该实例的名字
    char *name;     /* Master name from the point of view of this sentinel. */
    // 实例运行的id
    char *runid;    /* Run ID of this instance, or unique ID if is a Sentinel.*/
    // 配置纪元,用于实现故障转义
    uint64_t config_epoch;  /* Configuration epoch. */
    // 实例的地址
    sentinelAddr *addr; /* Master host. */
    ...
} sentinelRedisInstance;

 这里面有一个addr指针,保存着当前实例的ip地址和端口号,指向的是一个sentinelAddr实例,看代码如下所示:

typedef struct sentinelAddr {
    char *ip;	/* 实例的ip地址 */
    int port;	/* 实例的端口号 */
} sentinelAddr;

1.5 创建连向主服务器的网络连接

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

  1. 一个是命令连接,这个用于发送命令并接受回复消息;
  2. 一个是订阅链接,用于监听__sentinel__:hello频道。

2.获取主服务器的信息

 在初始化一个Sentinel实例并且连接到主服务器之后,Sentinel接下来会以每10s一次的频率,通过命令连接向所有被监视的主服务器发送INTO命令,并通过分析命令回复来获取服务器当前的状态信息。这里会包含两方面的信息,分别是:

  1. 一方面是关于主服务器本身的信息,比如run_id服务器运行id,role角色信息等;
  2. 主服务器下所有从服务器的信息,每个从服务器会通过一个“slave”字符串开头的行记录,基于此,Sentinel无需用户提供,就可以知道所有从服务器的信息。

 通过以上的回复信息,Sentinel就可以对主服务器实例结构的部分信息进行更新,而且会将从服务器的实例记录到主服务器的 slaves字典中,当然如果之前 slaves已经存在此从服务器的实例,会对这部分实例的内容进行更新,这是存在于sentinelRedisInstance里面的一个属性:

typedef struct sentinelRedisInstance {
    ...
    // 表示主服务器下的所有从服务器信息
    dict *slaves;       /* Slaves for this master instance. */
    ...
} sentinelRedisInstance;

 综上,Sentinel监视主从服务器的示意图如下:
在这里插入图片描述

3. 获取从服务器的信息

 通过第二步,Sentinel检测到了从服务器的存在,那么接下来,Sentinel除了会给从服务器创建实例外,还会创建连接到从服务器的命令连接和订阅连接。之后,Sentinel也会以每10s一次的频率通过命令连接向服务器发送 INTO命令。同理根据命令的回复,Sentinel会对从服务器的内容属性进行更新,包括从服务器的运行ID run_id,服务器的role,从服务器的复制偏移量,此从服务器对应主服务器的信息等。

4.发布与订阅消息

4.1 发布消息

 默认情况下,Sentinel会以2s一次的频率向所有监视的主服务器和从服务器,通过命令连接发送以下消息:

PUBLISH __sentinel__hello: "sentinel-ip,sentinel-端口号,sentinel-runid,sentinel-纪元,服务器名称,服务器ip,服务器端口号,服务器纪元"

 通过这条命令,所有服务器都会在这个__sentinel__:hello频道上执行发布操作。

4.2 订阅消息

 Sentinel与主服务器和从服务器建立连接后,会订阅此服务器__sentinel__:hello这个频道。也就是说,Sentinel既通过命令连接要求各服务器向这个频道发送消息,也从这个频道上接收消息,这是为什么呢?
在这里插入图片描述

 其实,对于监视同一个服务器的Sentinel来说,他们会通过监听这个频道获悉正在监听此服务器的其他Sentinel实例,用于更新自己的sentinels字典。所以在接收到__sentinel__:hello这个频道的消息后,Sentinel还要做下面这几件事情:

  1. 更新当前sentinel实例监听主服务器的sentinels字典:当一个Sentinel接收到来自其他Sentinel发来的问候消息时,会分析并提取出其他sentinel和master的参数,并检查自身的sentinels字典里面是否包含此sentinel实例,如果不包含就添加,如果包含会比对数据并进行更新。这里祭出源码:
typedef struct sentinelRedisInstance {
    ...
    // 表示监听当前主服务器下的所有sentinel实例(这里不包含当前的sentinel实例)
    dict *sentinels;    /* Other sentinels monitoring the same master. */
    ...
} sentinelRedisInstance;
  1. 创建与其他Sentinel的命令连接:在经历步骤1之后,如果发现了新的Sentinel实例,会创建一个连接到新Sentinel的命令连接,同理新Sentinel在收到新消息后也会创建与当前Sentinel的链接,最终所有的Sentinel之间,会形成一张相互连接的网络。这里需要注意一下,Sentinel实例之间不会创建订阅链接,所以其实是新上线的Sentinel通过与主服务的订阅链接告诉所有Sentinel实例,然后他们之间再互相创建命令连接。
    在这里插入图片描述

5. 检测主观下线状态

 OK,经过这么多复杂的过程后,Sentinel就会以每秒一次的频率向所有与他创建了命令连接的实例(我们来看一下这些实例有哪些,分别是主服务器、从服务器、其他Sentinel实例)发送PING消息,并通过对方的回复确定是否在线。
 如果实例在指定的时间内(down-after-milliseconds毫秒)没有回复,Sentinel会将此实例标记为下线的状态(flags = SRI_S_DOWN),此实例相对于此Sentinel就进入了主观下线状态。然而对于监视同一个服务器的多个Sentinel实例而言,由于设置的判断阈值时间不一样,会存在其他Sentinel实例判断此服务器仍然在线。

6. 检测客观下线状态

 当Sentinel将一个主服务器判定为主观下线后,为了防止因网络问题误判造成的假死结果,Sentinel会向其他所有的Sentinel实例咨询,当收到足够的主观下线回复后,就会将主服务器标记为客观下线,并进行故障转移,步骤如下:

  1. 源Sentinel向其他Sentinel实例发送询问命令 sentinel is-master-down-by-addr,命令中包含主服务器的ip、端口号、当前纪元等信息。
  2. 其他Sentinel实例接收 sentinel is-master-down-by-addr 命令后检查主服务器的状态(是否SRI_S_DOWN),并回复结果(是否主观下线)
  3. 源Sentinel接收其他Sentinel命令,当反馈的主服务器主观下线数量超过配置的阈值数量(quonum)时,将此服务器的客观下线状态标识(flags = SRI_O_DOWN)打开。

7. 选举领头Sentinel

 经过上面客观下线的判定后,监视下线主服务器的所有Sentinel会进行协商选举出一个领头Sentinel,由领头Sentinel对下线的主服务器进行故障转移。这里需要注意的是,检测主观和客观下线的可能不是一个Sentinel,由于时间先后顺序,监视同一个主服务器的Sentinel实例会陆续执行主观下线到客观下线的判定执行。下面我们看下选举领头Sentinel的选取规则:

  1. 最先判定客观下线的Sentinel实例(称为源1Sentinel)会向监视此服务器的所有Sentinel实例(目标Sentinel)发送 sentinel is-master-down-by-addr ,命令中会包含主服务器的ip、端口号、当前纪元,还有一个自身的runid。
  2. 目标Sentinel由于是首次收到领头Sentinel的选举,此时会将源1Sentinel设置为自身的leader,并给源1Sentinel回复一条命令,命令中包含源1的runid和当前纪元。后面再有其他Sentinel要求此目标Sentinel选举自身当leader的命令到来,都会被目标Sentinel拒绝,因为在当前纪元只能有一次选举权。
  3. 源1Sentinel接收到目标Sentinel的命令消息后,判断纪元和runid与自身的值是否相同,如果相同,那么表示目标已经将源1自己设置为领头Sentinel了。在向所有目标Sentinel发送完命后,如果源1收集到半数以上的回复后,就会成为最终的领头Sentinel。
  4. 下面其余陆续发现了服务器客观下线的源2/3/n…Sentinel,也会执行这些动作,看谁先能获得半数以上的投票就会成为leader。当然也可能在给定的时间内,没有一个Sentinel被选举为领头Sentinel,那就会过一段时间后,再次进行选举,步骤相同。

8. 故障转移

 经过第7步,在选举出领头Sentinel后,领头Sentinel会对已下线的主服务器执行故障转移操作,这里面包包含三个步骤:

  1. 从主服务器的从服务器中选举出一个状态良好、数据完整的从服务器,然后向这个从服务器发送slave no one,于是此从服务器转换为主服务器(server2)。这里选举的规则是:
    • 优先选择优先级最高的从服务器;
    • 其次选择偏移量比较高的从服务器;
    • 再次会按照运行ID进行排序,选取最小运行ID的从服务器;
  2. 向已下线主服务器(server1)的其余从服务器发送slaveof的命令,实现更换其余从服务器复制的主服务器目标。
  3. 将已下线的主服务器(server1)设置为从服务器,当已下线的主服务器再次上线时,领头Sentinel就会向他发送slaveof的命令,使得server1成为server2的从服务器。

9. 总结

 以上就是哨兵机制的实现原理,我整理自《Redis设计与实现这本书》,如果您觉得有问题,就给我留言吧,感谢关注和点赞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/52392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Express 4 快速入门 - 基本路由

Express Express 中文网 本文仅用于学习记录,不存在任何商业用途,如侵删 文章目录Express4 快速入门 - 基本路由4.1 什么是路由4.2 定义简单路由4.2.1 在主页回复字符串4.2.2 响应/应用程序主页根路由 ( ) 上的 POST 请求:4.2.3 响应对/user路…

订单超时自动取消3种方案——我们用这种!

大家好,大家对电商购物应该都比较熟悉了,我们应该注意到,在下单之后,通常会有一个倒计时,如果超过支付时间,订单就会被自动取消。 下单 今天,我们来聊聊订单超时未支付自动取消的几种方案。 1…

【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【02】Nacos、Feign、Gateway

持续学习&持续更新中… 学习态度:守破离 【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【02】微服务的几大组件SpringCloud Alibaba 简介简介为什么使用版本选择Nacos作为注册中心Feign声明式远程调用Nacos作为配置中心基本使用核心概念命名空间&#xff1…

【Linux】进程通信 | 信号

本篇博客让我们一起来康康信号部分的内容 系统为CentOS7.6,完整代码见 Gitee 文章目录1.什么是信号1.1 何为异步?1.2 信号的种类1.3 信号产生1.4 信号动作2.系统接口2.1 signal2.1.1 前台进程和后台进程2.1.2 循环捕捉所有信号2.1.3 信号9/192.2 kill2.2.1 killall…

人工智能数学基础--概率与统计13:连续随机变量的标准正态分布

一、引言 在《人工智能数学基础–概率与统计12:连续随机变量的概率密度函数以及正态分布》介绍了连续随机变量概率分布及概率密度函数的概念,并介绍了连续随机变量一个重要的概率密度函数:正态分布的概率密度函数的定义以及推导、使用场景&a…

培养出最多亿万富翁的美国大学TOP10榜单

若论世界大学排名,除了U.S. News、QS、软科、泰晤士这四大权威排名外,另有一些依据不同指标的排名。下面知识人网小编就推荐这份福布斯榜单给出的美国大学排名,供感兴趣的读者围观。 福布斯去年发布了一份全球亿万富豪榜(World’s…

怎么看网站域名有没有收录 收录情况怎么样 网站收录查询

对于网站收录的概念,互联网中或者搜索引擎中已经有大量的相关定义。网站收录,指的是爬虫爬取了网页,并将页面内容数据放入搜索引擎数据库中这一结果。 怎么看网站域名有没有收录?录情况怎么样? 用站长工具查询网站收录的操作步骤&#xff1…

[TIST 2022]No Free Lunch Theorem for Security and Utility in Federated Learning

联邦学习中的安全性和实用性没有免费午餐定理 No Free Lunch Theorem for Security and Utility in Federated Learning 目录摘要简介2 相关文献2.1 隐私测量2.2 联邦学习2.2.1 FL 中的威胁模型。2.2.2 FL 中的保护机制。2.3 隐私-实用权衡3 一般设置和框架3.1 符号3.2 一般设置…

前端如何实现网页变灰功能的?

备注:本文大量摘取前端充电宝公众号相关文章,大家感兴趣可以关注该公众号进行阅读学习 目录 1.引入 2.页面灰色实现方法 3.filter其他属性 A.blur():模糊 B.brightness():亮度 C.contrast():对比度 C.opacity()…

unity---Mesh网格编程(六)

目录 1.模型切割 2.代码 1.模型切割 如图,对3D模型的Mesh网格进行切割,会经过若干个三角面。而切割后,将会产生新的面来组成左右两边的物体。 要记录每个顶点与顶点下标,新的面要顺时针绘制, 2.代码 using System.…

docker+nginx 安装部署修改资源目录配置文件和容器端口信息

查看docker镜像 可以先查看docker下是否存在nginx镜像,使用如下这些命令查看: docker images: 列出所有镜像。docker images nginx: 列出所有nginx镜像,不同版本等等。docker search nginx: 搜索查看所有nginx镜像信息。 拉取安装nginx镜像…

Java8 函数式编程【基础篇】

Java 8是Java在保持向后兼容的前提下首次迈出重要一步,相比之前,不再是只对类库的改良,在编写复杂的集合处理、并行化执行、代码简洁度等方面都有颠覆性的提升。本文将探索和理解函数式编程的含义,以及它在Java 8中的实现。 一、…

RESTful API是什么?看完你整个人都通透了

要弄清楚什么是RESTful API,首先要弄清楚什么是REST? 01 REST REpresentational State Transfer,英语的直译就是“表现层状态转移”。如果看这个概念,估计没几个人能明白是什么意思。那下面就让我来用一句话解释一下什么是RESTf…

低代码搭建质量管理解决方案,为企业管理提速降本

市场竞争的越来越卷,越来越多的制造企业认识到质量管理的重要性。尤其随着全球经济化与信息化的到来,质量管理已经成为企业管理的关键环节。然而与国际上具有先进技术和管理水平的企业相比,我国企业的质量管理较为薄弱,存在着质量…

【MATLAB】羽状图

目录 羽状图 羽状图 h0figure(toolbar,none,...position,[200 150 450 350],...name,实例28);subplot(2,1,1)alpha90:-10:0;rones(size(alpha));malpha*pi/180;nr*10;[u,v]pol2cart(m,n);feather(u,v)title(羽状图)axis([0 20 0 10])subplot(2,1,2)t0:0.5:10;x0.05i;yexp(-x*t…

R语言解释生存分析中危险率和风险率的变化

危险率函数 让我们模拟R中的一些数据&#xff1a; n < - 10000 h < - 0.5 t < - -log&#xff08;runif&#xff08;n&#xff09;&#xff09;/ h 该代码模拟了危险函数的存活时间&#xff0c;即常数。 视频&#xff1a;R语言生存分析原理与晚期肺癌患者分析案…

Ajax学习:jQuery发送ajax请求 通用方法$.ajax

app.all(/jQuery,(requset,response)>{response.setHeader(Access-Control-Allow-Origin,*);const data{name:张三};let strJSON.stringify(data);//需要转换称为json 否则传递的任然是对象response.send(str);//3s之后返回给客户端 }) $(button).eq(2).click(function() {/…

MySQL和Oracle JDBC驱动包下载步骤

MySQL官网&#xff1a;https://www.mysql.com/ 步骤如下&#xff1a; 1.点击DOWNLOADS 2.往下滑&#xff0c;找到MySQL Community&#xff08;GPL&#xff09;Downloands并点击 3.点击Connector/J 4.当前页面展示的是最新版本&#xff0c;要下载历史版本点击Archives 5.选择…

15 【登录鉴权】

15 【登录鉴权-Cookie】 1.什么是认证&#xff08;Authentication&#xff09; 通俗地讲就是验证当前用户的身份&#xff0c;证明“你是你自己”&#xff08;比如&#xff1a;你每天上下班打卡&#xff0c;都需要通过指纹打卡&#xff0c;当你的指纹和系统里录入的指纹相匹配…

细数APDL中的流程控制命令

作者&#xff1a;水哥ANSYS&#xff0c;获授权转载 一、概述 有过其他编程语言经验的同学都知道&#xff0c;流程控制类语言命令在编程中是必须掌握的一门技巧&#xff0c;这类命令能大幅提高我们的编程效率&#xff0c;增加程序可读性。类似地&#xff0c;在APDL中也有很多的…