《Redis设计与实现》读书笔记(二十六) ——Redis哨兵(sentinel)启动与建立监听机制

《Redis设计与实现》读书笔记(二十六) ——Redis哨兵(sentinel)启动与建立监听机制

(原创内容,转载请注明来源,谢谢)

一、概述

哨兵(Sentinel)是redis高可用性的解决方案,由一个或多个哨兵实例组成的哨兵系统,可以监视任意多个主服务器,以及这些主服务器属下的从服务器。

当被监视的主服务器下线时,根据某些规则挑选一个从服务器,作为新的主服务器。接着,其他从服务器会向新的主服务器发送复制指令,并且完成复制。同时,哨兵会监视下线的原主服务器,在它重新上线后,将它也置为从服务器。

二、哨兵启动与初始化

1、启动命令

有两个命令,效果完全相同:

redis-sentinel /path/to/sentinel/config/sentinel.conf
或 redis-server/path/to/sentinel/config/sentinel.conf --sentinel

启动后,会做五件事:初始化服务器、将普通redis使用的代码替换成sentinel专用的代码、初始化sentinel状态、根据给定的配置文件去初始化监视的主服务器列表、创建连向主服务器的网络连接。

2、初始化服务器

由于sentinel服务器是特殊的redis服务器,因此其一开始的初始化服务器和redis普通的服务器初始化大体一致。区别在于sentinel不会载入rdb、aof文件。

3、使用sentinel专用代码

在载入常量、命令表时,会载入sentinel专用的内容。例如sentinel默认的端口是26379,命令表只有七个命令可以执行,包括ping、info、sentinel以及发布订阅相关的四个命令(不含publish命令),而且这七个命令的定义和普通的redis服务器也有所不同。

因此,客户端无法对sentinel服务器请求redis普通服务器的命令,如get、set等。

4、初始化sentinel状态

sentinel状态会初始化sentinelState结构体,这里面保存了sentinel特有的属性,普通的属性仍会初始化在redisServer结构体中。

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

上述即sentinelState结构体中的全部属性。

5、初始化sentinelState中的master属性

1)sentinelRedisInstance

master属性是字典形式保存这个sentinel监视的所有主服务器,键是服务器名称,值是指向sentinelRedisInstance指针。

每个sentinelRedisInstance结构(实例结构)是一个被sentinel监视的主服务器、从服务器或其他sentinel。

实例结构属性非常多,主要的属性:name表示服务器名称,从服务器和其他sentinel名称采用“ip:端口”的方式命名,主服务器由sentinel来自动命名;runid表示运行id;addr记录实例的地址;down_after_period记录主观下线时间;quorum表示接收到多少个投票后,服务器算是客观下线。

其中,addr的地址,是一个结构体,包括字符数组形式的ip以及int形式的端口号。

2)初始化

对sentinel的初始化会引起对masters字典的初始化,而masters字典的初始化,由载入的sentinel的配置文件决定。

例如如下配置文件:

则masters字典如下图所示:

其中的每一个sentinelRedisInstance如下图所示:

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

初始化的最后一步,即创建连向主服务器的网络连接。sentinel将成为主服务器的客户端,对它发送命令,并获取有关的回复。

sentinel会和每一个主服务器都创建两个连接,一个是命令连接,专门用于向主服务器发送命令与接收主服务器的回复;另一个是订阅连接,专门用于订阅主服务器的__sentinel__:hello频道。

由于发布订阅时候,信息都不会保存在redis服务器,为了保证保存hello频道的每一条信息,必须专门有一个订阅的连接。另外,除了订阅频道外,sentinel必须要能给主服务器发送命令,以此来与主服务器通信,因此命令连接也是必不可少的。

三、获取主服务器信息

sentinel默认会每10秒一次,给主服务器发送info命令,并且通过分析info命令,来判断当前主服务器的信息。

通过分析info命令,sentinel会得到两方面的信息:一是主服务器的运行ID以及其role域记录的服务器角色,二是关于主服务器属下所有从服务器的信息,由slave字符串开头,每行IP记录一个IP地址、端口号、offset(用于与主服务器aof)、lag(延迟时间)等。

因此,sentinel无序建立和从服务器的连接,也可以知道从服务器的情况。sentinel只需要将info获得的返回结果,分析并更新到sentinel的sentinelState结构体的相应属性即可。

另外,sentinel在更新结构体时,还会分析每一个从服务器是否存在,如果是现有的则更新结构体,如果不是现有的则新增一个结构体。

从上述可知,主从服务器sentinelRedisInstance的主要区别,一是flags属性主是SRI_MASTER而从是SRI_SLAVE;二是名称主服务器是sentinel起的,从服务器是IP:端口号;三是主服务器有个slaves属性,指向一个字典,该字典键是从服务器的IP:端口号,值是表示从服务器的sentinelRedisInstance。

四、获取从服务器信息

当sentinel发现有新的从服务器,除了会为其创建实例结构,还会与其建立连接,连接也是包括订阅连接和命令连接。且默认下,每十秒也会给从服务器发送info命令。

根据info命令,可以提取出以下主要信息:运行ID、角色、主服务器ip与端口、主从连接状态、从服务器优先级、从服务器偏移量。

五、向主服务器和从服务器发送信息

默认情况下,sentinel会每两秒一次,向监听的主从服务器发送以下格式的命令:

publish __sentinel__:hello “<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>”

其中,s开头的是监听的服务器相关的信息,m开头的是sentinel的信息。

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

1、接收信息

上面已经提到,sentinel会和每个监听的服务器建立发布订阅连接,监听__sentinel__:hello频道,会一直监听到连接断开为止。

采用发布订阅的方式,是因为如果不止一个sentinel监听该主从结构的各服务器,则当其中某一个sentinel发送上述第五步的publish的命令,服务器回复在频道信息的,可以被所有监听的sentinel获取到。

sentinel接收到信息将与sentinel的运行id进行比对,如果一致则表示信息是自身发送的,sentinel将丢弃不处理信息;如果不一致表示是其他sentinel发送的命令,则会进行比对并更新相应内容。

2、更新sentinels字典

sentinel为主服务器建立的sentinels字典除了保存自身信息,还会保存其他sentinel的信息,字典的键是sentinel的ip:port,值是对应的sentinel实例。

获取的结果中,如果已经存在名称,则是原来就有是sentinel,否则是新的sentinel则要新开一个空间进行存储。

整体的存储方式和存储主从服务器的方式基本一致。

3、创建连向其他sentinel的连接

当sentinel发现其他sentinel,不仅会记录其结构信息,还会建立一个命令连接,而新的sentinel也会向该sentinel建立命令连接。最终监视主服务器的多个sentinel将形成网络。

另外,sentinel不会和其他sentinel建立订阅连接,因为不需要订阅相关信息。sentinel之间发送命令和订阅信息,只需要互相用命令连接发送即可。

——written by linhxx 2017.09.13

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-09-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏闻道于事

HTML状态码大全(301,404,500等)

HTML状态码大全(301,404,500等)HTML状态码大全(301,404,500等)HTML状态码大全(301,404,500等)HTML状态码大全(...

3116
来自专栏还债之路

redis缓存服务器

#你当前没有指定配置文件,以默认的配置文件启动,如果你想指定配置文件你可以redis-server 文件所在位置

632
来自专栏技术博文

Cookie禁用了,Session还能用吗?

Cookie与Session,一般认为是两个独立的东西,Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案。 Cook...

31011
来自专栏枕边书

Redis “瘦身”指南

前言 Redis 应该是开发者最常用的缓存服务器了,它丰富的数据结构,快速高效的内存操作能帮助开发者迅速完成复杂功能的设计,可以说让人一旦使用过后很难再离开它了...

25510
来自专栏娱乐心理测试

网络请求返回HTTP状态码(404,400,500)

1775
来自专栏nummy

Django实现SSO

当用户(浏览器)访问我们的服务(第三方应用)时, 服务首先判断用户是否已经登录(其实就是判断请求中是否有sessionid),如果没有登录,则重定向至认证服务器...

853
来自专栏Pythonista

web service基础知识

<!-- p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px '.PingFang SC'; color: ...

673
来自专栏决胜机器学习

PHP网络技术(一)——HTTP协议

PHP网络技术(一)——HTTP协议 (原创内容,转载请注明来源,谢谢) 一、概述 HTTP协议是一个基于应用层的通信规范,通信双方都遵守此协...

3416
来自专栏Linyb极客之路

网络编程之HTTP协议的请求方法

HTTP是一个基于TCP/IP通信协议来传递数据,包括html文件、图像、结果等,即是一个客户端和服务器端请求和应答的标准。

1124
来自专栏FreeBuf

打造一款属于自己的远程控制软件(一)

本人为了工作中便于管理手中大量的计算机一直在寻找一款合适的远程控制软件。鉴于网上下载的远程控制软件大多都被不同程度地植入后门,于是萌生了自己打造一款远控的想法,...

5388

扫描关注云+社区