Redis通过引入一个或多个Sentinel实例组成的Sentinel系统以监视任意多个服务器,当主服务器进入下线状态时自动将从服务器升级为新的主服务器,然后由新服务器代替已下线的主服务器处理命令请求,达到提供高可用性的解决方案。
一、监控功能
Sentinel本质上是一个运行在特殊模式下的Redis服务器,所以初始化时不会载入RDB文件或者AOF文件,而是创建连向被监视主服务器的网络连接,Sentinel成为主服务器的客户端,通过向主服务器发送命令,获取相关信息。Sentinel会创建两个连向主服务器的异步网络连接:
(1)命令连接:向主服务器发送命令,并接收命令回复;
(2)订阅连接:订阅主服务器的_sentinel_:hello频道;
Sentinel默认以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复,来获取主服务器的相关信息:主服务器本身的信息(如服务器的运行ID等信息)和主服务器下的所有从服务器信息(只用提供主服务器信息,自动发现从服务器)。
Sentinel默认以每两秒一次的频率,通过命令连接向被监视的主从服务器_sentinel_:hello频道发送消息来宣告自己的存在。同时也会通过_sentinel_:hello频道接收其他Sentinel发来的信息,并根据这些信息为其他Sentinel创建相应的实例结构及命令连接。【Sentinel与主&从服务器创建命令连接和订阅连接,与其他Sentinel只创建命令连接!】
在sentinel.c/sentinelState结构中保存了服务器中所有和Sentinel功能相关的状态:
/* Sentinel 的状态结构 */
struct sentinelState {
// 当前纪元
uint64_t current_epoch; /* Current epoch. */
// 保存了所有被这个 sentinel 监视的主服务器
// 字典的键是主服务器的名字
// 字典的值则是一个指向 sentinelRedisInstance 结构的指针
dict *masters; /* Dictionary of master sentinelRedisInstances.
Key is the instance name, value is the
sentinelRedisInstance structure pointer. */
// 是否进入了 TILT 模式?
int tilt; /* Are we in TILT mode? */
// 目前正在执行的脚本的数量
int running_scripts; /* Number of scripts in execution right now. */
// 进入 TILT 模式的时间
mstime_t tilt_start_time; /* When TITL started. */
// 最后一次执行时间处理器的时间
mstime_t previous_time; /* Last time we ran the time handler. */
// 一个 FIFO 队列,包含了所有需要执行的用户脚本
list *scripts_queue; /* Queue of user scripts to execute. */
} sentinel;
其中,在sentinelState中的masters字典记录了所有被Sentinel监视的主服务器的相关信息:
字典的键:被监视主服务器的名字;
字典的值:被监视主服务器对应的sentinel.c/sentinelRedisInstance结构,该结构记录了实例的的相关信息,如IP地址和端口号;
二、故障转移
如下图所示,主服务器server1有3个从服务器server2、server3和server4,Sentinel系统对主从服务器进行监控。当监控系统察觉到主服务器server1下线时,会执行故障转移操作:
(1)挑选server1下的一个从服务器(这里为server2),将该服务器升级为主服务器;
(2)向server1下的其他服务器发送复制指令让其他从服务器成为新的主服务器的从服务器;
(3)同时Sentinel监控系统继续监控已下线的server1,如果发现它重新上线,则将其设置为主服务器的从服务器。
三、下线的判断
1、主观下线
Sentinel以默认每秒一次的频率向所有与它创建了命令连接实例(主服务器、从服务器、其他Sentinel)发送ping命令,并根据ping命令的回复判断实例是否在线。
有效回复:实例返回+PONG、-LOADING、-MASTERDOWN三种回复的其中一种;
无效回复:实例返回其他回复,或者没有回复;
如果一个实例在down-after-milliseconds配置的默认时间内连续向Sentinel返回无效的回复,那Sentinel会修改这个实例所对应的实例结构中的标志位,标识这个实例进入主观下线状态。
2、客观下线
当一个Sentinel将一个主服务器判断为主观下线后,会向监视这个主服务器的其他Sentinel进行询问,看它们是否也认为该主服务器已经进入了下线状态(可以主观下线、也可以是客观下线),当达一定数量的下线判断之后,Sentinel将服务器判定为客观下线,然后对主服务器进行故障转移操作。
参考资料
1、http://www.redis.net.cn/tutorial/3506.html
2、《Redis设计与实现》第二版---黄健宏
3、https://github.com/xingzhexiaozhu/redis-3.0-annotated
4、http://www.yiibai.com/redis/redis_strings.html