前言:
Sentinel是Redis高可用性解决方案,何为高可用,即主从两个Redis服务器,若主服务器挂了,通过Sentinel能切换到从服务器进行服务,不需要人为的切换。Sentinel实例组成的系统可以监视任意多个主服务器,当某个主服务器下线后,可以从这个主服务器下的从服务器中挑选出一个从服务器升级为新的主服务器,进行故障转移。
1.Sentinel的初始化:
Sentinel是一种特殊的redis服务器,Sentinel与redisServer的区别大致体现在下面几点 :
一个Sentinel的启动流程可以大概总结为:
结合代码观察下启动流程:在main函数中调用checkForSentinelMode(int argc, char **argv)函数判断这个redis服务器是否按照sentinel参数启动,代码如下,也同时看出可用两种命令方式启动Sentinel
第一种:redis-sentinel sentinel.conf
第二种:redis-server sentinel.conf --sentinel
函数返回值会保存在sentinel_mode中,server.sentinel_mode = checkForSentinelMode(argc,argv);
server.sentinel_mode为true时,调用initSentinel函数。代码如下
下图可看出sentinelcmds 与 redisCommandTable 命令大不相同。
2.Sentinel中保存的主服务器
Sentinel中masters字典保存了所有被Sentinel监视的主服务器,字典的键是监视服务器的名字,值是被监视的服务器对应的sentinelRedisInstance结构。
Tips:每个sentinelRedisInstance实例可以是一个主服务器,从服务器或者一个Sentinel这三种类型其一。
观察下图sentinelRedisInstance的部分成员
通过一个加载sentinel.conf配置,如图 ,创建一个sentinelRedisInstance实例。如图1-1(master2并未在写入配置,1-1中的master2只是表示:一个sentinel可监视多个主服务器。)
初始化sentinel的最后一步是创建与主服务器的连接。会创建两条连接
3.获取主服务器信息
sentinel以每10秒一次的频率通过命令连接向被监视的主服务器发送INFO命令。通过分析INFO命令的回复获取主服务器的当前信息。
通过INFO命令,获取主服务器的信息:
我启动了三个redis服务器,port 6379为主服务器,其余18181,12345为从服务器,则sentinel获取从服务器信息如下:
sentinel known-slave master1 127.0.0.1 18181
sentinel known-slave master1 127.0.0.1 12345,
sentinel根据获取的从服务器信息:
1.创建从服务器的实例保存到主服务器实例中的slaves字典中,如图1-1。
2.更新slaves字典中存在的slave实例对象。
从服务器实例结构flags值为SRI_SLAVE,而主服务器为SRI_MASTER;从服务器实例name属性为IP:PORT组成,主服务器为sentinel配置文件设置,即conf中的master1。
4.获取从服务器信息
sentinel获取到从服务器信息后,除了为从服务器创建实例,也会与从服务器建立两个网络连接。并且连接建立后,每10s发送一个INFO命令。根据命令回复,获取以下信息:
根据这些信息对从服务器的信息进行更新。
5.获取其余Sentinel的信息
Sentinel会以接近于(为何说接近,后文有写)2s一次的频率调用sentinelSendHello函数向主从服务器发送以下格式命令:
PUBLISH __sentinel__:hello <s_ip><s_port><s_uid><s_epoch><m_name><m_ip><m_port><m_epoch>
之前说Sentinel与主从服务器都会建立两条连接,其中订阅连接就会订阅__sentinel__:hello频道,即通过命令连接像服务器的__sentinel__:hello频道发送消息,也通过订阅频道接收消息。
对于监视同一个服务器的多个sentinel,一个sentinel发送的消息会被其他的sentinel通过__sentinel__:hello频道接收到,更新其他sentinel对于发送sentinel的认知,也会更新其他sentinel对于服务器的认知。即图1-1中的dict *sentinels,记录了出本sentinel外其余监视这个服务器的sentinel结构信息。
那么上述2s一次的调用从代码中如何体现?
具体函数调用过程如下
sentinelSendPeriodicCommands 函数中关于 sentinelSendHello的代码如下,ri是sentinelRedisInstance实例,这个实例中的last_pub_time记录了上次发送命令的时间,SENTINEL_PUBLISH_PERIOD 是一个宏定义#define SENTINEL_PUBLISH_PERIOD 2000,所以当前时间大于距离上次发送命令时间>2时,则再次发送命令。这便说明了为何说接近2s的时间发送一次。
6.创建与其他sentinel的命令连接
通过订阅频道获取到监视同一服务器的其他sentinel信息时,如图1-1中 dict * sentinels 字典所示,创建 或 更新其他sentinel实例。当发现一个新的sentinel创建相应实例结构后,还会与其创建一个命令连接,而这个新的sentinel也会创建一个命令连接到这个sentinel 。即两个sentinel之间存在两条连接,各自创建一条。正式因为这个命令连接互相交换消息,才实现了sentinel主观下线检测, 客观下线检测,以及sentinel选举 和最终目的故障转移,当主服务器挂了的时候,能够继续使用从服务器服务,并将从无服务器升级为主服务器。
7.主观下线检测
sentinel会以1s一次的频率向所有与它创建了命令连接的sentinelRedisInstance实例对象(即 主服务器 从服务器 其他sentinel)发送PING消息,sentinel实例中的down_after_millisecons指定了sentinel判断实例进入主观下线的时间长度,如果down_after_millisecons毫秒内,未收到有效回复,则sentinel会修改这个实例,将实例结构中的flags属性中的SRI_S_DOWN标识打开。
8.客观下线检测
8.1发送主观下线消息
当一个sentinel将主服务器判断为主观下线后,会调用函数 sentinelAskMasterStateToOtherSentinels,根据函数名字,也可以看出询问其他sentinel这个主服务器状态如何。这个函数会发送命令is-master-down-by-addr,其参数为主机ip,端口port,当前sentinel的配置纪元,第四个参数是一个条件表达式:
(master->failover_state > SENTINEL_FAILOVER_STATE_NONE) ?sentinel.myid : "*", 如果这个sentinel开启了故障转移状态则为sentinel的id,否则为 ‘*‘。在客观下线检测时,发送的则是‘*‘。
命令 SENTINEL is-master-down-by-addr 127.0.0.1 6379 0 * 表示当前主服务器IP为127.0.0.1 端口6379的主服务器被判断为主观下线。
8.2 回复主观下线消息
接收到这个命令的其余sentinel根据这个命令中的参数,检测服务器是否下线,并发送回复SENTINEL is-master-down-by-addr <state> <leader_runid><leader_epoch>
8.3 接收消息回复
根据其他sentinel返回的消息,如果认为服务器下线的数量超过该sentinel配置中quorum的值,那么该sentinel就认为主服务器进入客观下线状态,打开SRI_O_DOWN标识。
需注意,不同的sentinel配置判断客观下线的条件可能不同,一个sentinel认为客观下线时,未必达到其他sentinel配置的客观下线条件
比如 sentinel master monitor 127.0.0.1 6379 2 与 sentinel master monitor 127.0.0.1 6379 5,一个quorum值为2 一个为5,即一个认为有两个sentinel判断服务器下线,则可以判定为客观下线;另一个认为至少有5个sentinel判断服务器下线,才可判定为客观下线。
9.选举领头sentinel
当sentinel判断服务器客观下线后,就会进行故障转移,进行故障转移之前,要先选举出一个零头sentinel,有这个领头sentinel进行故障转移操作。不然10个sentinel监视,10个都执行故障转移,岂不是乱套了。
选举的规则和方法如下:
10.故障转移
选出领头sentinel后,将对下线的主服务器进行故障转移。
10.1 挑选新的主服务器
将挑选出的状态良好,数据完整的从服务器,发送slave no one命令,将其转为主服务器。发送slave no one 命令后,以每1s一次的频率向被升级从服务器发送INFO命令,观察其身份变化。
挑选的规则如下: 现将已下线的主服务器的从服务器保存到一个列表中
10.2 修改从服务器的复制目标
当挑选出新的主服务器后,将旧服务器中的从服务器全部执行SLAVEOF <ip><port> 拷贝这个新的主服务器
10.3 将旧的主服务器设置为从服务器
在旧的主服务器中保存设置,当其重新上线时,执行SLAVEOF命令,称为从服务器
原文:https://www.cnblogs.com/smallhehe/p/12275056.html