欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

redis 系列23 哨兵Sentinel (上)

程序员文章站 2022-06-25 08:21:58
一.概述 Sentinel(哨岗或哨兵)是Redis的高可用解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升 ......

一.概述

  sentinel(哨岗或哨兵)是redis的高可用解决方案:由一个或多个sentinel实例(instance)组成的sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

  1.1 下面是一个sentinel系统与主从服务器之间的关系:

redis 系列23 哨兵Sentinel (上)

    (1) 双环图案的server1是当前的主服务器,以及server2、server3、server4三个从服务器。

    (2) 三个从服务器复制主服务器的写入命令数据,实现数据同步。

    (3) sentinel系统则监视所有四个服务器。

 

  1.2  sentinel系统监视主服务器下线

    当主服务器server1进入下线状态,那么三个从服务器复制操作被中止,由sentinel系统监视到了server1已下线,当server1的下线时长超过用户设定的下线时长时,sentinel系统就会对server1执行自动故障迁移。下面是sentinel系统监视到了server1主服务器已下线:

redis 系列23 哨兵Sentinel (上)

    只有具备故障转移功能,才是一个高可用的解决方案。sentinel系统自动执行故障转移步骤:

    (1) 首先sentinel系统会挑选一个从服务器,并将这个选中的从服务器升级为新的主服务器。 

    (2) 之后 sentinel系统会让所有从服务器都开始复制新的主服务器,故障转移操作执行完毕。

    (3) sentinel系统还会继续监视已下线的server1,并在它重新上线时,将它设置为从服务器。

 

二. sentinel服务器初始化过程介绍

   2.1 初始化一个普通的redis服务器

    因为sentinel服务器本质上只是一个运行在特殊模式下的redis服务器,所以启动sentinel的第一步,就是初始化一个普通的redis服务器。初始化服务器在介绍“服务器章节”中讲到过。由于工作不同,sentinel的初始化过程和普通redis服务器的初始化过程并不完全相同。比如:sentinel就不会载入rdb文件或者aof文件。下面表格展示sentinel模式下运行时,服务器各个主要功能使用情况:

功能 使用情况
数据库和键值对方面的命令,如set,del,flushdb 不使用
事务命令,如multi和watch 不使用
脚本命令,如eval 不使用
rdb持久化命令,如save和bgsave 不使用
aof 持久化命令,如bgrewriteaof 不使用

复制命令,如slaveof

sentinel内部可以使用,但客户端不可以使用
发布与订阅命令,如publish和subscribe subscribe,psubscribe,unsubscribe,punsubscribe四个命令在sentinel内部和客户端都可以使用,但publish命令只能在sentinel内部使用
文件事件处理器,(负责发送命令请求,处理命令回复) sentinel内部使用,但关联的文件事件处理器与普通redis服务器不同
时间事件处理器,(负责执行servercron函数) sentinel内部使用,servercron函数会调用sentinel.c/sentineltimer函数,后者包含了sentinel要执行的所有操作

  

  2.2 服务器内部使用sentinel专用代码

    启动sentinel的第二个步骤就是将一部分普通redis服务器使用的代码替换成sentinel专用代码。比如:普通redis服务器端口6379,而sentinel端口26379,即sentinel.c/redis_sentinel_port常量。还有命令表也不一样,对于sentinel的客户端就只有ping, sentinel,info, subscribe,psubscribe,unsubscribe,punsubscribe 这7个命令,即sentinel.c/sentinelcmds作为服务器的命令表。

  

  2.3 初始化sentinel状态

    应用了专用代码之后,步骤三是服务器会初始化一个sentinel.c/sentinelstate结构,这个结构保存了服务器中所有和sentinel功能有关的状态,对于服务器一般状态还是由redis.h/redisserver结构保存。

 

  2.4 初始化sentinel状态的masters属性

    sentinel状态中的masters字典记录了所有被sentinel监视的主服务器的相关信息,其中字典的键是被监视的主服务器名字,而字典的值是被监视主服务器对应的sentinel.c/sentinelredisinstance结构。每个sentinelredisinstance实例结构代表监视一个redis服务器实例,这个实例可以是主服务器,也可以是从服务器,或者另外一个sentinel服务器。对于sentinel状态的初始化将引发对masters字典的初始化,而masters字典的初始化是根据被该入的sentinel配置文件(sentinel.conf)来进行的。

 

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

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

    (1) 一是命令连接,专门用于向主服务器发送命令,并接收命令回复。比如sentinel向主服务器发送:info命令。

    (2) 二是订阅连接,专门用于订阅主服务器的_sentinel_:hello频道。 比如sentinel向主,从,其它sentinel发送sentinel本身和主库信息。

    下面是一个sentinel监视两个主服务器master1和master2,创建命令连接和订阅连接图:

redis 系列23 哨兵Sentinel (上)

      命令连接:是sentinel用来对主服务器发送命令,以此来与主服务器进行通信,所以sentinel必须向主服务器创建命令连接。订阅连接:是redis在发布与订阅功能 中,被发送的信息都不会保存在redis服务器中,如果信息发送时,想要接收的客户端不在线或者断线,那么这个客户端就会丢失这条信息,因为为了不丢失_sentinel_:hello频道的任何信息,sentinel必须专门用一个订阅连接来接收该频道的信息。

      

三. 获取服务器信息

  3.1 sentinel获取主服务器信息

    sentinel默认会以每10秒一次的频率,通过命令连接向主服务器发送info命令,通过分析info命令的回复来获取主服务器的当前信息,就像在上篇讲到的复制功能,在客户端输入info replication 命令一样,sentinel可以获取以下两方面的信息:

    (1) 关于主服务器本身的信息,包括服务器run_id,role的服务器角色。

    (2) 关于所有从服务器的信息,每个从服务器都由一个slave字符串开头的行记录,记录了从服务器ip和端口(主服务器中有从库的配置信息)。

 

  3.2 sentinel获取从服务器信息

    当sentinel发现主服务器有新的从服务器出现时,sentinel除了会为这个新的从服务器创建相应的实例结构(sentinelredisinstance)之外,sentinel还会创建连接到从服务器的命令连接和订阅连接。sentinel默认会以每10秒一次的频率通过命令连接从服务器发送info命令,通过分析info命令的回复来获取从服务器的当前信息。包括:从服务器运行run_id、从服务器角色role、主服务器的ip及端口、主从服务器的连接状态master_link_status、从服务器的优先级slave_priority。

 

  3.3  sentinel向主从服务器发送信息

    在默认情况下, sentinel会以每2秒一次的频率,通过命令连接向,所有被监视的主服务器和从服务器发送以下格式的命令:

    redis 系列23 哨兵Sentinel (上)

    这条命令向服务器的_sentinel_:hello频道发送了一条信息,信息的内容由多个参数组成:

    (1) 以s_开头以参数记录的是sentinel本身的信息。

    (2) 而m_开头的参数记录的则是主服务器的信息,如果sentinel正在监视的是主服务器,那么这些参数就是主服务器的信息,如果sentinel正在监视的是从服务器,那么这些参数记录就是从服务器正在复制的主服务器的信息。

参数 描述
s_ip sentinel的ip地址
s_port sentinel的端口号
s_runid sentinel的运行id

s_epoch

sentinel 的当前配置纪元

m_name 主服务器的名字
m_ip 主服务器的ip地址
m_port 主服务器的端口号
m_epoch 主服务器的当前配置纪元

    以下是一条sentinel通过publish命令向主服务器发送的信息示例:

redis 系列23 哨兵Sentinel (上)

  

    这个示例中sentinel的ip地址为172.0.0.1端口号为26379, 运行id为后面一串,当前纪元为0。主服务器的名字为mymaster,ip地址为127.0.0.1,端口号为6379, 当前纪元为0。

 

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

    当sentinel与一个主服务器或者从服务器建立起订阅连接之后,sentinel就会通过订阅连接,向服务器发送以下命令:subscribe_sentinel_:hello 。对于每个与sentinel连接的服务器,sentinel既通过命令连向服务器的_sentinel_:hello频道发送信息,又通过订阅连接从服务器的_sentinel_:hello频道接收信息。

    当有三个sentinel,分别是sentinel1、sentinel2 、sentinel3。三个sentinel在监视同一个服务器,那么当sentinel1向服务器的_sentinel_:hello频道发送一条信息时,所有订阅了_sentinel_:hello频道的sentinel(包括sentinel1自己在内)都会收到这条信息。

    当一个sentinel从_sentinel_:hello频道收到一条信息时,sentinel会对这条信息进行分析,提取出信息中sentinel 的 ip 、port、runid等8个参数,并进行以下检查:

    (1) 如果信息中记录的sentinel运行id和接收信息的sentinel运行id相同,那么说明这条信息是sentinel自己发送的,sentinel将丢弃这条信息,不做进一步处理。

    (2) 相反地,如果信息中记录的sentinel运行id和接收信息的sentinel运行id不相同,那说明这条信息监视同一个服务器的其它sentinel发来的,接收信息的sentinel将根据信息中的参数,对相应主服务器的实例结构进行更新。

 

  3.5 sentinel更新自己的sentinels字典

    sentinel为主服务器创建实例结构中的sentinels字典,保存了sentinel本身,还监视这个主服务器的其他sentinel的资料。当一个sentinel接收到其他sentinels发来的信息时,接收的sentinel会从信息中分析并提取出两方面参数:

    (1)与sentinel有关的参数,包括sentinel的ip、port、runid、配置纪元。

    (2)与主服务器有关的参数, 包括监视主服务器的ip、port、runid、配置纪元。

    假设分别有三个sentinel: 127.0.0.1:26379、127.0.0.1:26380、127.0.0.1:26381。三个sentinel正在监视主服务器127.0.0.1:6379, 那么当127.0.0.1:26379这个sentinel接收到以下消息时:

redis 系列23 哨兵Sentinel (上)

    这个sentinel将执行以下动作:

    (1) 第一条信息发送者为自己,信息忽略。

    (2) 第二条信息发送者为26381, sentinel会根据信息提取出内容,对sentinels字典中26381对应的实例结构进行更新。

    (3) 第三条信息发送者为23680,同样更新字典中的23680对应的实例结构。

    每个sentinel都有自己的一个sentinels字典, 对于26379的sentinel它的sentinels字典信息保存了26380和26381两个sentinel信息。其它sentinel也一样。

 

  3.6 sentinel创建连向其他sentinel的命令连接

    当sentinel通过频道信息发现一个新的sentinel时,不仅更新sentinels字典,还会创建一个连向sentinel命令连接,而新的sentinel也会创建连向这个sentinel的命令连接,最终监视同一个主服务器的多个sentinel将形成相互连接的网络。如下图所示:

redis 系列23 哨兵Sentinel (上)