往期回顾
redis之数据结构与对象篇(一)
redis之数据结构与对象篇(二)
redis之数据结构与对象篇(三)
redis之数据结构与对象篇(终章)
redis之单机数据库杂谈
redis持久化的秘密
redis的复制实现
redis之发布与订阅
Sentinel(哨兵)是Redis的高可用性解决方案:由一个或者多个Sentinel实例组成Sentinel系统可以见识多个主服务器,以及这些主服务器属下的所有从服务器,并在被见识的主服务器进入下线状态时,自动将主服务器属下的从服务器升级为主服务器,然后由新的主从服务器代替已经下线的主服务器继续处理命令请求
假设这时,从服务器server1进入下线状态,那么从服务器server2,server3,server4对主服务器的复制操作将被终止,并且Sentinel系统会察觉到server1已经下线
当server1的下线时长超过用户设定的下线时长上线时,Sentinel系统就会对server1执行故障转移操作:
启动一个Sentinel可以使用命令:
$ redis-sentinel /path/you/sentinel.conf
当一个Sentinel启动时,它需要执行以下步骤:
Sentinel本质上是一个运行在特殊模式下的Redis服务器,所以启动的第一步就是初始化一个Redis服务器。Sentinel的作用和普通的Redis服务器不同,所以初始化过程也不相同
例如,普通服务器在初始化时会载入RDB文件或者AOF文件来还原数据库状态,但是Sentinel并不使用数据库,所以初始化Sentinel时就不会载入RDB文件或者AOF文件
Sentinel模式下,服务器的主要功能使用情况。
功能 | 使用情况 |
---|---|
键值对命令,SET,DEL等 | 不使用 |
事务命令,MULTI,WATCH | 不使用 |
脚本命令 | 不使用 |
RDB持久化命令 | 不使用 |
AOF持久化命令 | 不使用 |
使用Sentinel的第二个步骤就是将一部分普通Redis服务器使用的代码替换成Sentinel专有代码。比如说,普通Redis服务器使用redis.h/REDIS_SERVERPORT 常量的值作为服务器端口号:
#define REDIS_SERVERPORT 6379
而Sentinel则使用sentinel.c/REDIS_SENTINEL_PORT常量的值作为服务器端口:
#define REDIS_SERVERPORT 26379
除此之外,普通REDIS服务器使用redis.c/redisCommandTable作为服务器的命令列表
而Sentinel则使用snetinel.c/sentinelcmds作为服务器命令列表,并且其中的INFO命令在使用Sentinel模式下的专有实现sentinel.c/sentinelInfoCommand函数,而不是普通Redis服务器使用的实现redis.c/infoCommand函数
sentinelcmds命令表解释了Sentinel模式下,redis服务器不能执行SET,DEL等命令,因为服务器根本没有在命令表中载入这些命令。
PING,SENTINEL,INFO,SUBSCRIBE,UNSUBSCRIBE,PSUBSCRIBE,PUNSUBSCRIBE这七个命令就是客户端对Sentinel执行的全部命令
在应用了Sentinel专有代码之后,接下来服务器会初始化一个Sentinel.c/sentinelState结构,这个结构保存了服务器中所有和Sentinel功能有关的状态
struct sentinelState{
uint64_t current_epocj ;
//保存所有被这个sentinel监视的主服务器
//字典的键就是主服务器的名字
//字典的值则是一个指向sentinelRedisInstance结构的指针
dict *masters;
//是否进入TILT模式
int tilt;
//目前正在执行的脚本数量
int running_scripts;
//进入TILT模式的时间
mstime_t tilt_start_time;
//最后一次执行时间处理的时间
mstime_t previous_time;
//一个FIFO队列,包含了所有需要执行的用户脚本
list *scripts_queue;
} sentinel;
初始化Sentinel状态的masters属性
Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器的相关信息,其中:
对Sentinel状态的初始化将引发对masters字典的初始化,而nasters字典的初始化根据被载入的Sentinel配置文件来进行
初始化Sentinel的最后一步就是创建相连被监视主服务器的网络连接,Sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并且从命令回复中获取相关的信息
对于每个被Sentienl监视的主服务器,Sentinel会创建两个连向主服务器的连接:
Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并且通过分析INFO命令的回复来获取主服务器的当前信息
例如,主服务器master有三个从服务器slave0,slave1,slave2,那么Sentinel将持续向主服务器发送INFO命令
通过分析主服务器返回的INGO命令回复,Sentinel可以获取以下两方面信息:
根据run_id和role记录的信息,Sentinel将对主服务器的实例结构进行更新,例如,主服务器启动后,它的运行id不同,Sentinl检测到这一情况后,会对实例结构的运行ID进行更新
主服务器返回的从服务器信息,则会被用于更新主服务器实例结构的slaves字典,这个字典记录主服务器下的从服务器
Sentinel在分析INFO命令中包含从服务器信息,会检查从服务器的实例结构是否存在slaves字典中
主服务器实例结构和从服务器实例结构之间的区别
在默认情况下,Sentinel会以每两秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送以下格式的命令:
PUBLISH _sentinel_:hello ",,,,,,,"
这条命令向服务器的_sentinel_:hello频道发送一条消息,信息的内容由多个参数组成
当sentinel与一个主服务器或者从服务器建立起订阅连接之后,Sentinel会通过订阅连接,向服务器发送以下命令
SUBSCRIBE ——sentinel_:hello
Sentinel对此频道的订阅会一致持续到Sentinel与服务器的连接断开为止。
也就是说,对于每个与Sentinel连接的服务器,Sentinel即通过命令连接向服务器的sentinel_:hello频道发送信息,又通过订阅连接从服务器的频道接受信息
对于监视同一个服务器的多个Sentinel来说,一个Sentinel发送的信息会被其他Sentinel接收到,这些信息会被用于更新其他Sentinel对发送信息Sentinel的认知,也会被用于更新其他Sentinel对被监视服务器的认知
当一个Sentienal从_sentinel_:hello频道收到一条信息时,Sentinel会对这条信息进行分析,提取出信息中的Sentinel IP和端口号,进行以下检查
Sentinel为主服务器创建的实例结构中的sentinels字典保存了除Sentinel本身之外,所有监视这个主服务器的其他Sentinel资料:
当一个Sentinel接受到其他Sentinel发来的消息时,目标Sentinel会从信息中分析并提取出对应的参数:
根据信息中提取出来的主服务器参数,目标Sentinel会在自己的Sentinel状态的masters字典中查找相应的主服务器实例结构,然后根据提取出来的Sentinel参数,检查主服务器实例结构中的sentinels字典,源Sentinel是否已经存在:
在默认情况下,Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(主服务器,从服务器,其他Sentinel)发送PING命令,并且通过实例返回PING命令回复来判断是否在线
实例对PING命令回复可以分为以下两种情况:
Sentinel配置文件中制定了Sentinel判断实例进入主观下线需要的时间长度:如果一个实例在规定时间(down_afer_millseconds)毫秒内,连续向Sentinel返回无效回复,那么Sentinel会修改这个实例所对应的实例结构,在结构的flags属性中打开SRI_S_DOWN标识,以此来表示这个实例进入主观下线状态
检查客观下线状态
当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一主服务器的其他Sentinel进行询问,看他们是否也认为主服务器已经进入下线状态。当Sentinel从其他Sentinel那里接受到足够数量的已下线判断后,Sentinel就会将从服务器判断为客观下线状态,并且对主服务器执行故障转移操作
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel协商选举出一个领头的Sentinel,并由领头的Sentinel对下线主服务器执行故障转移操作
在选举产生出零头Sentinel之后,领头Sentinel对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤:
故障转移操作第一步要做的就是在已经下线的master的slaves中,挑选一个状态良好,数据完整的从服务器,然后向从服务器发送SLAVEOF no one命令,将这个从服务器转换为主服务器
上图展示在一次故障转移操作中,领头Sentinel向被选中的从服务器server2发送SLAVEOF no one命令
在发送SLAVEOF no one命令之后,领头sentinel以每秒一次的频率向升级的从服务器发送INFO信息,当被升级服务器的role从原来的slave变为master时,领头Sentinel就知道被选中的从服务器已经顺利升级为主服务器了
当新的主服务器出现后,领头Sentinel下一步就是,让已经下线的主服务器下的从服务器去复制新的主服务器,这一动作可以通过向从服务器发送SLAVEOF命令来实现
故障转移操作最后要做的就是,将已经下线的主服务器设置为新的主服务器的从服务器。
下图展示了旧的主服务器下线,当server1重新上线时,Sentinel向它发送SLAVEOF命令,让它成为server2的从服务器