上一篇 我们模拟了单机器下哨兵模式的搭建,那么接下来我们看下哨兵模式的实现与工作。

为什么又分成两篇呢?因为篇幅太长(偷懒),再一个这篇主要说的是Sentinel的初始化以及信息交换,下一篇着重说下状态检查、Sentinel头领选举与故障转移 。

启动并初始化Sentinel

当一个Sentinel启动时,需要执行以下步骤:

(1)初始化服务器。

因为Sentinel本事上是一个运行在特殊模式下的Redis服务器,所以启动时的第一步也就是初始化一个普通的Redis服务器。不同点是在初始化的时候不会载入RDB或AOF文件。

(2)将普通的Redis服务器使用的代码替换成Sentinel专用代码。

端口替换Redis服务器使用redis.h/REDIS_SERVERPORT(6379)常量作为服务器端口,而Sentinel则使用sentinel.c/REDIS_SENTINEL_PORT(26379)常量作为服务器端口。

另外Redis服务器使用redisCommandTable服务器作为命令表,而Sentinel则使用sentinelcmds作为服务器的命令表,并且其中的info命令会使用Sentinel模式下专用的sentinelInfoCommand函数,而不是普通redis服务器使用的redis.c/infoCommand函数。

(3)初始化Sentinel状态。

服务器会初始化一个sentinel.c/sentinelState结构('Sentinel状态'),用于保存服务器中所有和Sentinel功能有关的状态。

struct sentinelState{
//当前纪元,用于实现故障转移
uint64_t current_epoch;
//保存了所有被这个sentinel监视的主服务器
//字典的键是主服务器的名字
//字典中的值是一个指向sentinelRedisInstance结构的指针
dict *masters;
//是否进入TILT模式
int tilt;
//目前正在执行的脚本数量
int running_scripts;
//进图TILT模式的时间
mstime_t tilt_start_time;
//一个FIFO队列,包含了所有需要执行的用户脚本
list *scripts_queue;
} sentinel;

(4)根据给定的配置文件,初始化Sentinel的监视主服务器列表。

sentinelRedisInstance结构(实例结构)

typedef struct sentinelRedisInstance{
//标识值,记录了实例的类型以及该实例的当前状态
int flag;
//实例的名称(主服务器由用户配置,从服务器自动设置ip:port)
char *name;
//实例的运行id
char *runid;
//配置纪元,用户实现故障转移
uint64_t config_epoch;
//实例的地址
//sentinelAddr *addr;
//实例无相应多少毫秒之后才会被判断主观下线
mstime_t down_after_period‘;
//判断这个实例为客观下线所需要支持的投票数量
int quorun;
//在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量
int parallel_syncs;
//刷新故障迁移状态的最大时间限制
mstime_t fallover_timeout;
} sentinelRedisInstance;

*addr 指向sentinelAddr结构:

typedef struct sentinelAddr{
char *ip;
int port;
} sentinelAddr;

根据用户的配置初始化实例结构:

#名称 ip port

sentinel monitor mymaster 127.0.0.1 6379 2

#实例在相应多少毫秒之后才会被判断主观下线

sentinel down-after-milliseconds mymaster 3000

sentinel failover-timeout mymaster 10000

#在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量

sentinel parallel-syncs mymaster 1

(5)创建连向主服务器的网络连接。

Sentinel将称为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关的信息:对于被Sentinel监视的主服务器来说,Sentinel会创建两个连向主服务器的异步网络连接,一个是命令连接这个连接专门用于向主服务器发送命令,并接收命令回复;另一个是订阅连接这个连接专门用于订阅主服务器的_sentinel_:hollo频道。

 获取主服务器信息

sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息。

通过分析主服务器返回的INFO命令回复,Sentinel可以获取以下两个方面的信息:

一方面是关于主服务器本身的信息,包括run_id域记录的服务器运行ID以及role域记录的服务器角色;另一方面是关于主服务器属下的所有从服务器信息,每个从服务器由一个“slave”字符串开头的行记录,每行的ip=域记录了从服务器的IP地址,而port=域则记录了从服务器的端口号。根据这些IP地址和端口号,Sentinel无须用户提供从服务器的地址信息,就可以自动发现从服务器。

主服务器 实力结构的flags属性的值为SRI_MASTER,而从服务器实例结构的flags属性的值为SRI_SLAVE。

当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。

在默认情况下,Sentinel会以每两秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送以下格式的命令,PUBLISH _sentinel_:hello "< s_ip > < s_port >< s_runid >< s_epoch > < m_name > < m_ip >< m_ip ><m_epoch>"。

接收来自主服务器和从服务器的频道信息

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

当一个Sentinel从__sentinel__:hello频道收到一条信息时,Sentinel会对这条信息进行分析,提取出信息中的Sentinel IP地址,Sentinel端口号,Sentinel运行ID等八个参数,并进行检查:如果信息中记录的Sentinel运行ID和基尔兽信息的Sentinel的运行ID相同,那么说明这条信息时Sentinel自己发送的,Sentinel将丢弃这条信息,不做处理,反之如果记录的Sentinel运行ID和接收消息的Sentinel的运行ID不相同,那么说明这条信息时监视同一个服务器的其他Sentinel发来的,接收信息的Sentinel将根据这些信息中的参数,对相应主服务器的实例结构进行更新。

Sentinel为主服务器创建的实例结构中的sentinels字典中除了保存本身以外,还会保存同样监视这个主服务器的其他Sentinel的资料,其中字典键为 ip:port 值为Sentinel实例结构。

如果目标Sentinel(接收消息的Sentinel)接收到源Sentinel(发送消息的Sentinel)的消息,提取其中的参数检查主服务器实例结构的sentinels字典中源Sentinel实例结构是否存在,如果存在则更新,不存在则创建实例结构并存储到主服务器的sentinels字典中。并且,目标Sentinel还会创建连接向源Sentinel的命令连接,最终监视同一主服务器的多个Sentinel将形成互相连接的网络。

但是Sentinel之间不对创建订阅连接,这是因为Sentinel需要通过接收主服务器或者从服务器发来的频道信息发现未知的新Sentinel,所以才需要建立订阅连接,而相互已知的Sentinel只要使用命令连接来进行通信就足够了。


每天学一点,总会有收获。

下篇我们看下Redis的Sentinel(哨兵)的状态检查、Sentinel头领选举与故障转移。

说明:尊重作者知识产权,文中内容参考《Redis设计与实现》,仅在此做学习与大家分享。


Redis学习笔记(十五)Sentinel(哨兵)(中)的更多相关文章

  1. python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...

  2. (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)

    一.数据块 数据块是在S7 CPU的存储器中定义的,用户可以定义多了数据块,但是CPU对数据块数量及数据总量是有限制的. 数据块与临时数据不同,当逻辑块执行结束或数据块关闭,数据块中的数据是会保留住的 ...

  3. Redis学习笔记(六、哨兵)

    目录: 基本概念 环境部署 哨兵原理 哨兵命令 基本概念: 1.什么是哨兵 我们先从字面意思来了解哨兵,哨兵是对执行警戒任务的士兵的统称:在redis中哨兵也是一样,他监控着redis服务器的状态. ...

  4. (C/C++学习笔记) 十五. 构造数据类型

    十五. 构造数据类型 ● 构造数据类型概念 Structured data types 构造数据类型 结构体(structure), 联合体/共用体 (union), 枚举类型(enumeration ...

  5. Java学习笔记十五:Java中的成员变量和局部变量

    Java中的成员变量和局部变量 一:成员变量: 成员变量在类中定义,用来描述对象将要有什么 成员变量可以被本类的方法使用,也可以被其他类的方法使用,成员变量的作用域在整个类内部都是可见的 二:局部变量 ...

  6. Redis6.x学习笔记(五)哨兵

    前言 最近学习Redis6.x,特做笔记以备忘,与大家共学.课程是从私塾在线下载的,他们把架构师课程都放出来了,大家可以去下载学习,不要钱的,地址是http://t.hk.uy/eK7,课程很不错,值 ...

  7. Redis学习笔记(五) 基本命令:Hash操作

    原文链接:http://doc.redisfans.com/hash/index.html 学习前先明确一下概念,这里我们把Redis的key称作key(键),把数据结构hash中的key称为fiel ...

  8. Redis 学习笔记(五)高可用之主从模式

    上一节提到了 Redis 的持久性,也就是在服务器实例宕机或故障时,拥有再恢复的能力.但是在这个服务器实例宕机恢复期间,是无法接受新的数据请求.对于整体服务而言这是无法容忍的,因此我们可以使用多个服务 ...

  9. MySQL学习笔记十五:优化(2)

    一.数据库性能评测关键指标 1.IOPS:每秒处理的IO请求次数,这跟磁盘硬件相关,DBA不能左右,但推荐使用SSD. 2.QPS:每秒查询次数,可以使用show status或mysqladmin ...

  10. salesforce 零基础开发入门学习(十五)salesforce中formula的使用(不含Date/Time)

    本文参考官方的formula介绍PDF:https://resources.docs.salesforce.com/200/latest/en-us/sfdc/pdf/salesforce_usefu ...

随机推荐

  1. CF1285 --- Dr. Evil Underscores

    CF1285 --- Dr. Evil Underscores 题干 Today as a friendship gift, Bakry gave Badawy \(n\) integers \(a_ ...

  2. 多方法解决设置width:100%再设置margin或padding溢出的问题

    2019独角兽企业重金招聘Python工程师标准>>> 当设置了父元素的宽度,子元素设置宽度为100%后再在加上子元素上添加padding或margin值就会溢出.举个例子: < ...

  3. 上传组件Fine Uploader在ASP.NET中的应用

    现如今,世面上流行着许多前端上传组件,例如:Uploadify(http://www.uploadify.com/),Fine Uploader,等等.这篇博客从头开始,介绍如何在ASP.NET MV ...

  4. mock-server 之 mock 接口测试

    1.mock 介绍 mock 除了用在单元测试过程中,还有一个用途,当前端开发在开发页面的时候,需要服务端提供 API 接口,此时服务端没开发完成,或者说没搭建测试环境,这个时候前端开发会自己 moc ...

  5. Jenkins 节点配置

    1.配置代理 系统管理---configure Global Security(全局安全设置)---Tcp port for inbound agents---指定端口 服务器防火墙中开放此端口(li ...

  6. Android控件重叠显示小记

    方案一 利用布局控件显示优先级 在xml中RelativeLayout,FrameLayout,靠后的控件显示在上层. 利用margin属性 margin属性可以控制控件间的距离,属性值为正值时,越大 ...

  7. javaweb系统调优方案

    1. java代码优化 java代码优化6大原则 : https://blog.csdn.net/bunny1024/article/details/72803708 java代码优化: https: ...

  8. vue跳转的两种方法

    1 标签跳转 <router-link to='two'><button>点我到第二个页面</button></router-link> 2 点击事件跳 ...

  9. 最长公共子串(Longest common substring)

    问题描述: 给定两个序列 X=<x1, x2, ..., xm>, Y<y1, y2, ..., yn>,求X和Y长度最长的公共子串.(子串中的字符要求连续) 这道题和最长公共 ...

  10. python恺撒密码 与 字符串反码 【chr()与ord()函数的两种不同应用】

    恺撒密码  描述 恺撒密码是古罗马凯撒大帝用来对军事情报进行加解密的算法,它采用了替换方法对信息中的每一个英文字符循环替换为字母表序列中该字符后面的第三个字符,即,字母表的对应关系如下:‪‬‪‬‪‬‪ ...