Sentinel是Redis的高可用解决方案,由1-n个Sentinel实例组成的Sentinel系统,用来监视redis集群的主服务器,在主服务器下线时,自动将某个从服务器升级为新的主服务器,用来代替主服务器继续处理命令请求。
例如,server1因为某种原因下线,Sentinel系统发现,就会将某个子服务器升级为新的主服务器,当server1再次上线时,就会变为server2的从服务器。
(双环为主服务器,单环为从服务器)
Sentinel本质是运行在特殊模式下的redis服务器,只是在初始化的部分和功能有所差别。

启动Sentinel会将一部分普通的reids服务器使用的代码替换成Sentinel的代码。
Sentinel服务器初始化一个sentinel.c/sentinelState结构,保存了服务器中所有和Sentinel又能有关的状态。
struct sentinelState {
// 当前纪元, 用于实现故障转移
uint64_t current_epoch;
//保存了所有被这个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监视的主服务器的相关信息,其中:
字典的键是被监视主服务器的名字;
字典的值则是被监视主服务器对应的sentinel.c/sentinelRedisInstance结构。
每个sentinelRedisInstance结构代表一个被Sentinel监视的的Redis服务器实例(可以是主/从服务器,也可以是另外的Sentinel)。
SentinelRedisInstance实例部分的结构如下:
typedef struct sentinelRedisInstance {
//标识值, 记录了实例的类型, 以及该实例的当前状态
int flags;
//实例的名字
//主服务器的名字由用户在配置文件中设置
//从服务器以及Sentinel的名字由Sentinel自动设置
//格式为ip:port, 例如"127.0.0.1:26379"
char *name;
//实例的运行ID
char *runid;
//配置纪元, 用于实现故障转移
uint64_t config_epoch;
//实例的地址
sentinelAddr *addr;
// SENTINEL down-after-milliseconds选项设定的值
//实例无响应多少毫秒之后才会被判断为主观下线(subjectively down)
mstime_t down_after_period;
// SENTINEL monitor <master-name> <IP> <port> <quorum>选项中的quorum参数
//判断这个实例为客观下线(objectively down) 所需的支持投票数量
int quorum;
// SENTINEL parallel-syncs <master-name> <number>选项的值
//在执行故障转移操作时, 可以同时对新的主服务器进行同步的从服务器数量
int parallel_syncs;
// SENTINEL failover-timeout <master-name> <ms>选项的值
//刷新故障迁移状态的最大时限
mstime_t failover_timeout;
// ...
} sentinelRedisInstance;
sentinelRedisInstance.addr指向sentinel.c/sentinelAddr结构的指针,保存着实例的IP和端口号:
typedef struct sentinelAddr {
char *ip;
int port;
} sentinelAddr;
对Sentinel的初始化,会引发对masters字典的初始化,masters字典的初始化是根据被载入的Sentinel配置文件来进行的。如果指定的配置文件为以下内容:
#####################
# master1 configure #
#####################
sentinel monitor master1 127.0.0.1 6379 2
sentinel down-after-milliseconds master1 30000
sentinel parallel-syncs master1 1
sentinel failover-timeout master1 900000
#####################
# master2 configure #
#####################
sentinel monitor master2 127.0.0.1 12345 5
sentinel down-after-milliseconds master2 50000
sentinel parallel-syncs master2 5
sentinel failover-timeout master2 450000
那么Sentinel将作为主服务器的master1和master2创建如下结构:
Sentinel会创建两个连向被监视的主服务器的网络连接:
__sentinel__:hello频道
Sentinel默认10秒一次,通过命令连接向被监视的主服务器发送INFO命令,通过回复来获取主服务器的当前信息
当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构之外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。
默认情况下,Sentinel会以2秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送一下格式的命令:
PUBLISH sentinel:hello “<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>”
这条命令向服务器的__sentinel__:hello频道发送了一条信息
当Sentinel与一个主或从服务器简历起订阅连接之后,Sentinel就会通过订阅连接,向服务器发送以下命令:
SUBSCRIBE sentinel:hello
Sentinel对__sentinel__:hello频道的订阅会一直持续到Sentinel与服务器断开连接为止。
也就是说,对于每个与Sentinel连接的服务器,Sentinel即通过命令连接向服务器的__sentinel__:hello频道发送信息,又能通过订阅连接从服务器的__sentinel__:hello频道接受信息。

默认情况下,Sentinel会以每秒一次的频率向所有与它创建命令连接的实例发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。
当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向其他同样监视这一主服务器的其他Sentinel进行询问,看他们是否也认为主服务器已经进入了下线状态。当Sentinel从其他Sentinel哪里接收到足够数量的已下线判断之后,Sentinel就会将从服务器判定为客观下线,并对主服务器进行故障转移操作。
在选举产生出领头Sentinel之后, 领头Sentinel将对已下线的主服务器执行故障转移操作, 该操作包含以下三个步骤:
1) 在已下线主服务器属下的所有从服务器里面, 挑选出一个从服务器, 并将其转换为主服务器。
2) 让已下线主服务器属下的所有从服务器改为复制新的主服务器。
3) 将已下线主服务器设置为新的主服务器的从服务器, 当这个旧的主服务器重新上线时, 它就会成为新的主服务器的从服务器。
内如主要来自《Redis设计与实现》,自己学习整理用