作者:Wen Hui
转载:中间件小哥
Sentinel 使用和Redis服务器相同的事件处理机制:分为文件事件和时间事件。文件事件处理机制使用I/O 多路复用来处理服务器端的网络I/O 请求,例如客户端连接,读写等操作。时间处理机制则在主循环中周期性调用时间函数来处理定时操作,例如服务器端的维护,定时更新,删除等操作。Redis服务器主时间函数是在server.c中定义的serverCron函数,在默认情况下,serverCron会每100ms被调用一次。在这个函数中,我们看到如下代码:
其中当服务器以sentinel模式运行的时候,serverCron会调用sentinelTimer函数,来运行Sentinel中的主逻辑,sentinelTimer函数在sentinel.c中的定义如下:
Sentinel Timer函数会做如下几个操作:
1. 检查Sentinel当前是否在Tilt 模式(Tilt模式将会在稍后章节介绍)。
2. 检查Sentinel与其监控主备实例,以及其他Sentinel实例的连接,更新当前状态,并在主实例下线的时候自动做主备倒换操作。
3. 检查回调脚本状态,并做相应操作。
4. 更新服务器频率(调用serverCron函数的频率),加上一个随机因子,作用是防止监控相同主节点的Sentinel在选举Leader的时候时间冲突,导致选举无法产生绝对多的票数。
其中SentinelHandleDictOfRedisInstances函数的定义如下:
SentinelHandleDictOfRedisInstances函数主要做的工作是:
1.调用sentinelHandleDictOfRedisInstance函数处理Sentinel与其它特定实例连接,状态更 新,以及主备倒换工作。
2. 如果当前处理实例为主实例,递归调用SentinelHandleDictOfRedisInstances函数处理其下属的从实例以及其他监控这个主实例的Sentinel。
3. 在主备倒换成功的情况下,更新主实例为升级为主实例的从实例。
其中在sentinelHandleRedisInstance的定义如下:
这个函数会做以下两部分操作:
1. 检查Sentinel和其他实例(主备实例以及其他Sentinel)的连接,如果连接没有设置或已经断开连接,Sentinel会重试相对应的连接,并定时发送响应命令。 需要注意的是:Sentinel和每个主备实例都有两个连接,命令连接和发布订阅连接。但是与其他监听相同主备实例的Sentinel只保留命令连接,这部分细节会在网络章节单独介绍。
2. 第二部分操作主要做的是监测主备及其他Sentinel实例,并监测其是否在主观下线状态,对于主实例来说,还要检测是否在客观下线状态,并进行相应的主备倒换操作。
需要注意的是第二部分操作如果Sentinel在Tilt模式下是忽略的,下面我们来看一下这个函数第二部分的的具体实现细节。
sentinelCheckSubjectivelyDown 函数会监测特定的Redis实例(主备实例以及其他Sentinel)是否处于主观下线状态,这部分函数代码如下:
主观下线状态意味着特定的Redis实例满足以下条件之一:
1. 在实例配置的down_after_milliseconds时间内没有收到Ping的回复。
2. Sentinel认为实例是主实例,但收到实例为从实例的回复,并且上次实例角色回复时间大于在实例配置的down_after_millisecon时间加上2倍INFO命令间隔。
如果任何一个条件满足,Sentinel会打开实例的S_DOWN标志并认为实例进入主观下线状态。
主观下线状态意味着Sentinel主观认为实例下线,但此时Sentinel并没有询问其他监控此实例的其他Sentinel此实例的在线状态。
sentinelCheckObjectivelyDown 函数会检查实例是否为客观下线状态,这个操作仅仅对主实例进行。sentinelCheckObjectivelyDown函数定义如下:
这个函数主要进行的操作是循环查看监控此主实例的其他Sentinel SRI_MASTER_DOWN 标志是否打开,如果打开则意味着其他特定的Sentinel认为主实例处于下线状态,并统计认为主实例处于下线状态的票数,如果票数大于等于主实例配置的quorum值,则Sentinel会把主实例的SRI_O_DOWN标志打开,并认为主实例处于客观下线状态。
sentinelStartFailoverIfNeeded函数首先会检查实例是否处于客观下线状态(SRI_O_DOWN标志是否打开),并且在2倍主实例配置的主备倒换超时时间内没有进行主备倒换工作,Sentinel会打开SRI_FAILOVER_IN_PROGRESS标志并设置倒换状态为SENTINEL_FAILOVER_STATE_WAIT_START。并开始进行主备倒换工作。主备倒换的细节将在主备倒换的章节里介绍。
参考资料:
https://github.com/antirez/redis
https://redis.io/topics/sentinel
Redis设计与实现第二版黄健宏著