当一个sentinel启动时,需要下面的几个步骤
-
初始化哨兵服务器
-
将普通Redis服务器使用的代码替换出Sentinel专用代码
-
初始化sentinel状态
-
根据配置文件,初始化Sentinel的监视主服务器列表
-
创建连向主服务器的网络连接
[](()初始化Sentinel服务器
Sentinel本质上只是一个运行在特殊模式下的Redis服务器,所以它的初始化步骤和普通的Redis服务器差不多(回看前面的服务器),但要注意的是:Sentinel的初始化过程与普通的Redis服务器并不是完全一致,比如Sentinel不需要恢复数据,所以不需要去进行载入RDB文件或者AOF文件
下面看看Sentinel模式下的Redis可以用哪些命令
| 功能 | 使用情况 |
| — | — |
| 数据库和键值对方面的命令 | 不使用 |
| 事务命令 | 不使用 |
| 脚本命令 | 不使用 |
| 持久化命令,RDB与AOF | 不使用 |
| 主从复制命令 | Sentinel服务器内部会使用,但连接上Sentinel的客户端不可以使用 |
| 发布与订阅命令 | 订阅的4个命令都可以被Sentinel服务器内部和其客户端使用,但发布的命令(PUBLISH)只可以在Sentinel内部使用 |
| 文件事件处理器(前面提到过,这个处理器负责接收命令请求和处理命令回复) | Sentinel内部使用,但关联的文件事件处理器与普通的Redis不同 |
| 时间事件处理器(执行ServerCron函数) | Sentinel的内部使用,时间事件的处理器仍然是去执行ServerCron函数,但该模式下会调用sentinelTime函数,这个函数包含了Sentinel要执行的定时操作 |
[](()使用Sentinel的专用代码
现在已经初始化一台Sentinel服务器了,但里面的一些结构和代码是普通的Redis服务器的,此时要将替换成Sentinel专用的结构和代码
比如前面提到为什么Sentinel有一些命令不能用,就是因为其把redisCommandTable(服务器状态里面的命令表属性)替换成了sentinelcmds(Sentinel专用的命令)。
这也是为什么在Sentinel模式下,并不能执行一些键值对操作命令,因为压根没有载入这些命令,载入的命令只有下面的7个
-
info(查看服务器状态)
-
ping(访问)
-
sentinel(哨兵的命令,其实这个对应的是哨兵配置文件里面的参数,客户端可以进行修改)
-
subscribe(订阅)
-
unsubscribe(退订)
-
psubscribe(订阅指定格式的频道)
-
punsubscribe(退订指定格式的频道)
[](()初始化Sentinel状态
初始化Sentinel服务器后,有了自己的RedisServer状态,然后将一些原来的代码替换成Sentinel专用的代码后,接下来就是要初始化Sentinel状态(实际只是创建这个实例),这个状态其实是SentinelState结构
注意:服务器状态还是保存在RedisServer结构中,而Sentinel状态则保存在sentinelState结构中
结构里面的属性如下所示
struct sentinelState(
unit64_t current_epoch; //记录当前纪元,用于实现故障转移的
//保存了监视的所有主服务器的字典
//字典的键就是主服务器的名字
//而字典的值是一个指向sentinelRedisInstance(实例)结构的指针
dict *master;
//是否进入了TILT模式
int tilt;
//目前正在执行脚本的数量
int running_scripts;
//进入TILT模式的时间
mstime_t previous_time;
//最后一次执行时间处理器的时间
mstime_t previous_time;
//一个FIFO队列,包含了所有需要执行的用户脚本
list *scripts_queue;
)sentinel;
[](()初始化Sentinel状态的masters属性
初始化Sentinel状态后,就开始给里面的属性赋值了,下面就是载入配置文件,然后去初始化master属性
Sentinel状态 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 中的masters字典记录了所有被Sentinel监视的主服务器的相关信息
-
字典的键是被监视主服务器的名字(就是配置选项里面的mymaster)
-
而字典的值则是被监视的主服务器对应的sentinelRedisInstance结构
每一个SentinelRedisInstance结构都代表着一个被Sentinel监视的一个Redis服务器实例,不一定是主服务器,也可以是从服务器,甚至是另一个Sentinel,SentinelRedisInstance里面的属性很多,下面只介绍SentinelRedisInstance为主服务器时候的属性
typedef struct sentinelRedisInstance(
//标识值,记录了实例的类型,以及实例的当前状态
int flags;
//实例的名字(在配置文件那里载入)
//如果是从服务器或者另一个sentinel,名字是由sentinel自己设置的
//格式为:ip:port,
char *name;
//实例的运行ID
char *runid;
//配置纪元,也是用来实现故障转移的
unit64_t config_epoch;
//实例的地址
sentinelAddr *addr;
//实例无响应杜少毫秒之后被判断为主观下线(主观下线是指,哨兵自己认定监视的主服务器挂了)
//对应日志里面的就是+sdown(subjectively down)
//对应的是配置文件里面的sentinel down-after-millseconds参数
mstime_t down_after_period;
//判断这个实例为客观下线所需要的投票数量
//对应的就是配置文件里面的sentinel monitor
//的quorum参数,也就是指至少多少个哨兵认为这台服务器是主观下线,就会变成客观下线
int paraller_syncs;
//刷新故障迁移状态的最大时限
//对应配置未见里面的sentinel failover-timeout 选项的值
//也就是后面ms的值
//改属性是指:主服务器被认为客观下线,会被踢掉,然从服务器替代成为新的主服务器
//然后其余的从服务器要对新的主服务器进行复制(主从复制)
//但这个复制时间是可以设置限制的,超过这个时间限制就判定无效,需要重来
mstime_t failover_timeout;
//…
)
可以看到下面的slave名字为:ip地址:端口号