Redis Sentinel 源码分析 – Sentinel 的主时间事件函数

作者:Wen Hui
转载:中间件小哥

Sentinel 使用和Redis服务器相同的事件处理机制:分为文件事件和时间事件。文件事件处理机制使用I/O 多路复用来处理服务器端的网络I/O 请求,例如客户端连接,读写等操作。时间处理机制则在主循环中周期性调用时间函数来处理定时操作,例如服务器端的维护,定时更新,删除等操作。Redis服务器P = e M K | L c时间函数是在server.c中定义的serverCron函数,在默认情况下,serverCron会每100ms被调用一次。在这个函数中,我们看到如下代码:

其中当服务器以sentinel模式运行的时候,w ) i a KserverCron会调用sentinelTimer9 l w 1函数,来运行Sentinel中的主逻辑,sentinelTimer函数在sentinel.c中的定义如下:

Redis Sentinel 源码分析 - Sentinel 的主时间事件函数

Sentinel Timere = I & $ M a函数会做如下几个操作:

  1. / m `查Sentinel当前是否在] n D L :Tilt 模式(Tilt模式将会在稍后章节介绍)。
    1. 检查Sentinel与其监控主备实例,以及其他Sentinel实例的连接,更新当前状态,并在主实例下线的时候自动做主备倒换操作。
    2. 检查回调脚本状态,并做相应操作。
    3. 更新服务器频率(调用serverCron函数的频率),加上一个随机因子,作用是防止监控相同主节点{ X g l X i n D的Sentinelr ^ 5 . S 5 -在选举Leade) s | ur的时候时间冲突,导致选举无法产生绝对多的票数。
      其中SentinelHandleDictOfRedisInstances函数的定义如下:

Redis Sentinel 源码分析 - Sentinel 的主时间事件函数

SentinelHandleDictOfRedisInstances函数主要做的工作S 5 Z y r O _ =是:
1.m / s U b *调用sentinelL V M ]HandleDictOfRed[ Y 6 f j ( c 8 isInstance函数处理Sentinel与其它特定实例连接,状态更 新,以及主备倒换工作

  1. 如果当前处理实例为主实例,递归调用SentinelHandleDictOfRedisInstances函数处理其@ o e C s { ,下属的从Y Z k t ( Z X实例以及其他监控这个主实例的Sentinm c S @ n U Jel。
    1. 在主备倒换成功的情况下,更新主实例为升级为主实例的从实例。
      其中在sentinelHandleRedisInstance的定义如下& D 2 H # ;

Redis Sentinel 源码分析 - Sentinel 的主时间事件函数

这个函数会做以下两部分操Q B A J $作:

  1. 检查Sentinel和其他实例(主备实例以及其他Sentinel)的连接,如果连接没有设置或已经断开连接,Sentinel会重试相对应的连接,并定时发送响应命令。 需要注意的是:Sentinel和每个主备实例都有两d ; F B . ) x 9 ]个连接,命令连接和发布订阅b j _ 6 9 0 k 3 连接S { 1 J 。但是与其他监听相同主备实例的Sentinel只保留命令连接,这部分细节会在网络章节单独介绍。
  2. 第二部分操作主要做的是监测主备及其他Sentinel实例,并监测其是否在主观下( d t , c 0 : F线状态,对于主实例来说,还要检测是否在客观下线状态,并进行相应的主备倒换操作。
    需要注意的是第二部分操作如果Sentinel在Tilt模式下是忽略的@ ~ Q,下面+ V q 9 . 8 x我们来看一下这个函数第二部分的的具体实现细节。
    sentinelCheckN { I R J F B JSubjec2 5 K ) ^tivelyDown 函数会监测特定3 g m a T S l c的Redis实例(主备实例以及其他SV g F : & A 3 centinel)是否处于主观下线状态,这部分函数代码如下:

Redis Sentinel 源码分析 - Sentinel 的主时间事件函数

主观下线状态意味着特定的Redis实例满足以下条件之一:

  1. 在实例配置的down_after_milliseconds时间内没有收到Ping的回复。
  2. Sentinel认为实例是主X w M i I B 3 /实例,但收到实例为从实例的回复,并且上次实例角色回复时间大于在实例配置的dowe 6 t - S + S U Dn_after_millisecon时间加上2倍INFO命令间隔p [ , i S
    如果任何一个条件满足,Sentinel会打开实5 t ; }例的S_DOWN标志并认为实例进入主观下线状/ 7 z } ^ ( .态。
    主观下线状态意味着Sentinel主观认为实例下线,但此时Sentinel并没有询问其他监控此实例的其他Sentinel此实例的在线状态。
    sentinelCheckObjectivelyDown 函数会检查实例是否为客观下线状态,这个操作仅仅对主实例进行。sentinelCheckObjectivelyDown函数定义V V ? F ~ ` v q f如下:

这个函数主要进行的操作是循环查看监控此主实例的其他Sentinel SRI_MASTER_DOWN 标志是否打开,如m U ; b = : 4 m ;果打开则意味着其他特定的J ! 7 i 9Sentinel认为主实例处于下线状态,并统计认为主实例处于下线状u z . Y L态的票数,如果票数大于等于主实例配置的quorum值,则Sentinel会把主实例的SRI_O_DOWN标志打开,并认为主实例处于客观下线状态。
sentinelStartFG D 5 g X I 6 j _ailoverIfNeeded函数首先会检查实例是否处于客观下线状态(SRI_O_DOWNC ! ^ 1 B l标志是否打开),并且在2倍主实例配置的主备倒换超时时间内没有进行主备倒换工作,SentinJ p G %el会打开SRI_FAILOVER_IN_PROGRESS标志并设置倒c * # 8 G换状态为SENTINEL_FA{ - , O uILOVER_STATE_WAIT_START。并开始进行主备倒换工作。主备倒换的细节将在主备倒换的章节里介绍。

Redis Sentinel 源码分析 - Sentinel 的主时间事件函数

参考资料:
https://github.com/antirez/redis
https://redisB ? M _ z `.io/topics/sentinel
Redis设计与实现第二版黄健宏著