《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 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

2017年企业版高薪运维经典基础面试题汇总

1.解释下什么是GPL,GNU,自由软件? GPL:(通用公共许可证):一种授权,任何人有权取得、修改、重新发布自由软件的权力。 GNU:(革奴计划):目标是创...

3986
来自专栏北京马哥教育

运维架构师进阶:Linux进程管理

来源:IBM 译者:ljianhui 链接:blog.csdn.net/ljianhui/article/details/46718835 1.1 Linu...

3279
来自专栏python学习指南

python爬虫(四)_urllib2库的基本使用

本篇我们将开始学习如何进行网页抓取,更多内容请参考:python学习指南 urllib2库的基本使用 所谓网页抓取,就是把URL地址中指定的网络资源从网络...

20210
来自专栏北京马哥教育

Linux性能及调优指南:进程管理

Linux进程管理 进程管理是操作系统的最重要的功能之一。有效率的进程管理能保证一个程序平稳而高效地运行。 Linux的进程管理与UNIX的进程管理相似。它...

3636
来自专栏WindCoder

《Linux内核分析》之触发一个系统调用实验总结

系统调用列表中可用的很多,可惜对用代码进行系统调用不太清楚,只好从网上窃取了一份,地址在最后放上。此处以fork()为例。

883
来自专栏编程

Go语言的网络编程简介

文 | 源小白 共9877字,阅读需25分钟 本文通过 Go 语言写几个简单的通信示例,从 TCP 服务器过渡到 HTTP 开发,从而简单介绍 net 包的运用...

2337
来自专栏信安之路

轻松了解 web 日志分析过程

日志分析,其实涵盖的面是很广的,什么地方都可以有日志。而本篇文章主要针对 web 日志做一下分析。因为之前去学校里授课的时候有讲过一次,感觉内容挺不错的,就写到...

1802
来自专栏求索之路

现代操作系统部分章节笔记二、进程与线程三、存储管理

二、进程与线程 1.进程 1.进程模型: 1.有自己的程序地址空间,程序计数器、寄存器和变量当前值。 2.切换进程的时候程序计数器、寄存器会装载到真正的相应物...

3057
来自专栏coding for love

进程与线程,单核与多核1. 简介2. 程序3. 进程4. 线程5. 多进程与多线程的选择6. 小结参考

用户打开浏览器,其实就是打开了浏览器应用程序。那么什么是程序呢?我们常说浏览器是多线程的,JS 是单线程的,那么什么是线程呢?说到线程,和我们常说的进程有什么关...

1783
来自专栏IT笔记

Nginx学习之HTTP/2.0配置

哎呀,一不小心自己的博客也是HTTP/2.0了,前段时间对网站进行了https迁移并上了CDN,最终的结果是这酱紫的(重点小绿锁,安全标示以及HTTP/2.0请...

37214

扫码关注云+社区