一、介绍
Redis 通过 Sentinel系统保证自身的高可用性。Sentinel系统是由一个或者多个Sentinel实例组成,如图1和图2所示:它会实现的监视Redis 服务器主机机器及其从机的运行状态,当某个服务器主机被Sentinel系统认为客观下线的时候,Sentienel 系统的是从其可用的从机中选取一个升级为新的主机,下线主机则会成为新主机的从机,重新上线会从新的主机中同步数据。
二、Sentienl 实例
Sentienl实质也是一个redis的服务器的,但是但不承担数据的读写任务只负责监视起的其他redis服务器。作为sentienl 运行的服务器和普通服务器在启动时加载的指令集也是不一样的,只加载用通信和监视的几个指令(ping, sentinel, subscribe, unsubscribe, psubscribe, punsubscribe, info,其中info 是专有的)。
三、Sentinel 相关源码解析
-
struct sentinelState
sentinelState 包含sentinel 运行时的所有状态和监视服务主机状态信息。
struct sentinelState {
//sentinel 实例ID
char myid[CONFIG_RUN_ID_SIZE+1];
uint64_t current_epoch;
// 所监视redis 服务主机实例及信息
dict *masters;
int tilt;
int running_scripts;
mstime_t tilt_start_time;
mstime_t previous_time;
list *scripts_queue;
char *announce_ip;
int announce_port;
unsigned long simfailure_flags;
int deny_scripts_reconfig;
} sentinel;
-
struct sentinelRedisInstance
sentinelRedisInstance 表示一个被监视的Redis服务器的状态和相关信息。
typedef struct sentinelRedisInstance {
//标识主机状态
int flags;
//服务器名
char *name;
// 服务器运行实例
char *runid;
uint64_t config_epoch;
//服务器地址
sentinelAddr *addr;
...
//其他的sentinel服务器信息
dict *sentinels;
// 服务器从机
dict *slaves;
// 主机客观下线标准
unsigned int quorum;
...
// 主机主观下线标准
mstime_t master_link_down_time;
...
} sentinelRedisInstance;
四、Sentinel如何监视主机服务器
- Sentinel 会和每个被监视的Redis服务器创建两个异步网络链接。
- 命令链接:向服务器发送命令,并接受回复
- 订阅链接:订阅服务器的 __sentinel__:hello 频道
- Sentinel 默认以每10秒一次的频率向被监视服务器,发送INFO指令,服务器收INFO指令后,会返回自身信息和从机信息等。Sentinel 接受之后会解析主机的信息和从机的信息(运行id, ip, port等等),然后更新sentienlRedisInstance中保存的主机信息(name, runid等等)和从机信息(slaves). 保存从机的信息的是一个键为地址(ip:port),值为sentinelRedisInstance字典类型,主机和从机都是通过sentinelRedisInstance保存信息, 通过设置flags 参数(SRI_MASTER,SRI_SLAVE) 可以区分主机和从机。
- 获取到从机地址后,Sentinel 也会和从机创建命令链接和订阅链接,通过INFO,实时的获取从机信息,并更新保存
五、Sentinel 间如何相互协调
- Sentienl 在主从服务器建立好链接,会通过命令链接,订阅服务器的__sentinel__:hello频道
- Sentinel 会通过命令链接 以默认2秒一次的频率去向所有被监视的主服务器的__sentinel__:hello频道发送订阅信息。这个订阅信息包含sentinel 自身信息和接收命令的服务器信息(ip, port, id等)。所有订阅__sentinel__:hello的sentinel均可以收到信息。
- 通过订阅频道Sentinel之间可以获取对方的信息和其监视主机的信息,然后更新自身保存的服务器主机的信息,也将其他sentinel的信息进行保存。
- 通过从订阅频道获取到其他sentinel信息,sentinel之前也会建立命令链接进行通信和协调。
六、故障转移
- 主观下线:Sentinel 会以固定频率和和其建立命令链接的redis实例(主机,从机,sentinel)发送PING指令,根据回复判断其是否下线。若其在一定时间内无法进行有效回复,sentinel则认为该实例进入主观下线状态。其实主观下线可以理解某个sentinel基于自己的认知(网络时延,超时设置)对于某个实例是否下线的判断,所以不同的sentinel对于同一的redis实例的主观下线的判断可能时不一致的。
- 客观下线:当一个sentinel 认为某个实例主观下线了,他就和其他的sentinel进行沟通(命令链接),看看其他的sentinel 对于这个实例的判断,若一个sentinel 系统超过半数认为这个实例已经下线,则认为这个实例客观下线状态。
- 选取领头的Sentinel
通过Raft 算法sentinel 之间投票选举出来Leader(详情见后文) - 故障转移
- Leader 从下线主机服务器的从机服务器中选出最合适的从机服务器,将其升级为新的主机服务器
- 让其他从机服务器复制新的主机服务器
- 让下线的主机服务器成为新的主机服务器的从机,当其重新上线的时候,复制主机服务器。
七、Sentinel Leader选举
1. 规则
- 每个sentinel 节点都可以成为Leader
- sentinel 记录着选举回合数,每次选取无论是否成功回合数+1.
- 每个回合每个sentinel只有一次投票的机会。
2. 方法
- 每个发现服务器客观下线的sentinel,开始选举的时候,如果没有投票,就会投票给自己,并通过is-master-down-by-addr命令要求其他的sentinel 给自己投票, 其余sentinel收到指令会把自己投票结果返回给该sentinel.
- 投票是遵守选到先得的原则,sentinel 在没投票的情况下先收到的谁的指令就投给谁票。
- 每个sentinel 统计获得票数,如果超过半数就自动成为leader, 进行故障转移操作,并不需要通知其他的sentinel, 但他们观察的新的主机产生,自动结束选举。
- 或没有sentinel 获得过半票数,进行新一轮选举。每个sentinel 开新选举的时间不一(会有固定延时+一个1s以内的随机时间)。