redis 系列23 哨兵Sentinel (上)

一.概述

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

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

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

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

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

 

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

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

    只有具备故障转移功能,才是一个高可用的解决方案。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,创建命令连接和订阅连接图:

      命令连接:是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秒一次的频率,通过命令连接向,所有被监视的主服务器和从服务器发送以下格式的命令:

    

    这条命令向服务器的_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命令向主服务器发送的信息示例:

  

    这个示例中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接收到以下消息时:

    这个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将形成相互连接的网络。如下图所示:

 

posted on 2018-12-14 17:31  花阴偷移  阅读(832)  评论(0编辑  收藏  举报

导航