文章目录
一、Sentinel 的创建流程
1. 简介
Sentinel(哨岗、哨兵)是Redis的高可用性(high availability)解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求
其中seever1为主服务器,剩下的为从服务器
假设这时,主服务器server1进入下线状态,那么从服务器server2、server3、server4对主服务器的复制操作将被中止,并且Sentinel系统会察觉到server1已下线,如下图(下线的服务器用虚线表示)
当server1的下线时长超过用户设定的下线时长上限时,Sentinel系统就会对server1执行故障转移操作,具体操作如下
- Sentinel系统会挑选server1属下的其中一个从服务器,并将这个被选中的从服务器升级为新的主服务器
- Sentinel系统会向server1属下的所有从服务器发送新的复制指令,让它们成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕
- Sentinel还会继续监视已下线的server1,并在它重新上线时,将它设置为新的主服务器的从服务器
若server1下线,Sentinel系统选择新的主服务器的过程如下
如果此期间server1重新上线了,那么它会降级成为从服务器
2. 启动并初始化Sentinel
可以使用命令启动Sentinel
redis-sentinel sentinel.conf
或者
redis-server sentinel.conf --sentinel
当一个Sentinel启动时,它需要执行以下步骤
- 初始化服务器
- 将普通Redis服务器使用的代码替换成Sentinel专用代码
- 初始化Sentinel状态
- 根据给定的配置文件,初始化Sentinel的监视主服务器列表
- 创建连向主服务器的网络连接
以下对上述步骤逐一介绍
① 初始化服务器
Sentinel本质上只是一个运行在特殊模式下的Redis服务器,所以启动Sentinel的第一步,就是初始化一个普通的Redis服务器。不过,因为Sentinel执行的工作和普通Redis服务器执行的工作不同,所以Sentinel的初始化过程和普通Redis服务器的初始化过程并不完全相同
例如:普通服务器在初始化时会通过载入RDB文件或者AOF文件来还原数据库状态,但是因为Sentinel并不使用数据库,所以初始化Sentinel时就不会载入RDB文件或者AOF文件
② 使用Sentinel专用代码
启动Sentinel的第二个步骤就是将一部分普通Redis服务器使用的代码替换成Sentinel专用代码
例如
- 端口号配置普通Redis服务器使用redis.h/REDIS_SERVERPORT常量的值作为服务器端口
# define REDIS_SERVERPORT 6379
- 而Sentinel则使用sentinel.c/REDIS_SENTINEL_PORT常量的值作为服务器端口
# define REDIS_SENTINEL_PORT 6379
- 普通Redis服务器使用redis.c/redisCommandTable作为服务器命令表,而Sentinel则使用sentinel.c/sentinelcmds
③ 初始化Sentinel状态
在应用了Sentinel的专用代码之后,接下来,服务器会初始化一个sentinelState结构(后面简称“Sentinel状态”),这个结构保存了服务器中所有和Sentinel功能有关的状态(服务器的一般状态仍然由redisServer结构保存)。其代码如下
struct sentinelState {
char myid[CONFIG_RUN_ID_SIZE+1]; /* This sentinel ID. */
// 当前纪元,用于故障转移
uint64_t current_epoch; /* Current epoch. */
// 保存了被该哨兵监视的主服务器(多个)
// 使用字典,键是主服务器的名字,值是指向主服务器(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