- 前言
- 1. 启动并初始化 Sentinel
- 2. Sentinel 与服务器间的默认通信
- 3. 接受来自主服务器和从服务器的频道信息
- 4. 检测主观下线状态
- 5. 检查客观下线状态
- 6. 选举领头 Sentinel
- 7. 故障转移
- 最后
前言
参考资料:《Redis设计与实现 第二版》;
第四部分为多机数据库的实现,主要由以下模块组成:复制、Sentinel、集群;
本篇将介绍 Redis 的Sentinel功能。Sentinel(哨兵)是 Redis 的高可用解决方案:由一个或多个 Sentinel 实例(instance)组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器。在被监控的主服务器下线时,自动将下属的某个从服务器升级为主服务器,替代旧主服务器继续处理命令请求;
与本章相关的 Redis 命令总结在下篇文章,欢迎点击收藏,本篇将不再重复:
《Redis常用命令及示例总结(API)》:https://www.cnblogs.com/dlhjw/p/15639773.html
1. 启动并初始化 Sentinel
- 使用以下命令:
-
$ redis-sentinel /path/to/your/sentinel.conf
; -
$ redis-server /path/to/your/sentinel.conf --sentinel
;
-
- Sentinel 启动步骤:
- 1)初始化服务器:初始化一个普通的 Redis 服务器,与普通服务器稍有区别,如下:
- 2)使用 Sentinel 专属代码:使用
sentinel.c/sentinelcmds
作为服务器的命令表,因此在 Sentinel 模式下,只能执行 PING、SENTINEL、INFO、SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE、PUNSUBSCRIBE 七个命令; - 3)初始化 Sentinel 状态:初始化一个
sentinel.c/sentinelState
结构,该结构保存了服务器中所有和 Sentinel 功能有关的状态; - 4)初始化 Sentinel 状态的 masters 属性:masters 属性是一个字典,记录了所有被 Sentinel 监视的主服务器的相关信息(图16-6);
- 字典的键是被监视主服务器的名字;
- 字典的值是被监视主服务器对应的
sentinel.c/sentinelRedisInstance
结构(图16-5);-
sentinelRedisInstance
结构里有一个addr
指针,指向实例的 IP 地址和端口号;
-
- 5)创建连向主服务器的网络连接:对于每个被监视的主服务器,Sentinel 都会创建两个连向主服务器的异步网络连接:
- 命令连接:专门用于向主服务器发送命令,并接收命令回复(Sentinel 是主服务器的客户端);
- 订阅连接:专门用于订阅主服务器的
__sentinel__:hello
频道;
- 1)初始化服务器:初始化一个普通的 Redis 服务器,与普通服务器稍有区别,如下:
2. Sentinel 与服务器间的默认通信
2.1 获取主服务器信息
- Sentinel 默认每 10 秒向主服务器发送 INFO 命令;
- Sentinel 可以获得两方面信息:
- 主服务器本身信息,如:
run_id
、role
(服务器角色); - 主服务器下属所有从服务器信息,在以
slave
开头的字符串里;
- 主服务器本身信息,如:
- Sentinel 会根据主服务器返回的信息做相应更新;
- 主从服务器在
sentinelRedisInstance
结构上的区别:- flags 属性:主服务器为 SRI_MASTER;从服务器为 SRI_SLAVE;
- name属性:主服务器为用户配置文件规定;从服务器为 IP:端口号;
2.2 获取从服务器信息
- 当 Sentinel 发现新的从服务器后,会创建一个新的实例结构,同时创建连接到这个从服务器的命令连接和订阅连接;
- 创建命令连接后,Sentinel 默认每 10 秒向从服务器发送 INFO 命令;
- Sentinel 会根据从服务器返回的信息做相应更新;
2.3 向主服务器和从服务器发送信息
- Sentinel 默认每 2 秒通过命令连接向所有被监视的主从服务器发送以下格式命令:
-
PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
; -
各参数含义如下:
参数 含义 s_ip Sentinel 的 IP 地址 s_port Sentinel 的端口号 s_runid Sentinel 的运行 ID s_epoch Sentinel 当前的配置纪元 m_name 主服务器的名字 m_ip 主服务器的 IP 地址 m_port 主服务器的端口号 m_epoch 主服务器当前的配置纪元
-
3. 接受来自主服务器和从服务器的频道信息
- 当 Sentinel 与一个主服务器或从服务器建立订阅连接后,Sentinel 会通过订阅连接,向服务器发送以下命令:
-
SUBSCRIBE __sentinel__:hello
;
-
- Sentinel 既通过命令连接向服务器的
__sentinel__:hello
频道发送信息,又通过订阅连接从服务器的__sentinel__:hello
频道接受信息; - 当多个 Sentinel 监视一个服务器时,可以通过
__sentinel__:hello
频道的获取信息:- 如果信息中记录的 Sentinel 运行 ID 跟本Sentinel 一样,说明信息是自己发出的,丢弃这条信息;
- 反之,说明是其他 Sentinel 发出的;
3.1 更新 Sentinel 字典
- 一个 Sentinel 可以通过分析接收到的频道信息获知其他 Sentinel 的存在,并通过发送频道信息来让其他 Sentinel 知道自己的存在;
- 当目标 Sentinel 接受到源 Sentinel 的消息后,会查找主服务器实例结构的
sentinels
字典:- 如果源 Sentinel 存在,对源 Sentinel 的结构进行更新;
- 反之,说明源 Sentinel 是刚刚监视主服务器,将其添加到主服务器实例结构的
sentinels
字典里;
- 需要注意与从服务器的区别:
sentinels
字典里的源 Sentinel 的flags
属性为 SRI_SENTINEL;而从服务器为 SRI_SLAVE; - 下图为 127.0.0.1:26379 的 Sentinel 为主服务器创建的实例化,其他两个 Sentinel (端口号为26380和26381)也会为主服务器创建自己的实例化;
3.2 创建连向其他 Sentinel 的命令连接
- 当目标 Sentinel 通过通道信息发现一个新的源 Sentinel 时,会做两件事:
- 为该源 Sentinel 在
sentinels
字典里创建相应的示例结构; - 创建一个连向该源 Sentinel 的命令连接;
- 为该源 Sentinel 在
4. 检测主观下线状态
- Sentinel 默认每秒向与它建立的所有实例(包括主服务器、从服务器和其他 Sentinel)发送 PING 命令;
- 实例对 PING 命令的回复有两种情况:
- 有效回复:实例返回 +PONG、-LOADING、-MASTERDOWN 三种之一;
- 无效回复:返回其他;
- Sentinel 配置文件中的
down-after-milliseconds
选项指定 Sentinel 判断实例进入主观下线所需的时间; - 不同 Sentinel 所设置的主观下线时长可能不同;
- 如果某个实例在该时间内已知返回无效回复,Sentinel 会打开该实例
flags
的 SRI_S_DOWN 标识;
5. 检查客观下线状态
- 当 Sentinel 将一个主服务器判断主观下线后,会询问其他 Sentinel。当从其他 Sentinel 接受到足够数量的已下线判断后,Sentinel 会将从服务器判断为客观下线,并对主服务器执行故障转移操作;
5.1 发送 SENTINEL is-master-down-by-addr 命令
-
源 Sentinel 使用以下命令询问其他 Sentinel 是否同意主服务器已下线:
-
SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
;参数 说明 ip 被 Sentinel 判断为主观下线的主服务器的 IP 地址 port 被 Sentinel 判断为主观下线的主服务器的端口号 current_epoch Sentinel 当前的配置纪元,用于选举领头 Sentinel runid 可以是 * 符合(用于检测主服务器的客观下线状态)或 Sentinel 的运行 ID(用于选举领头 Sentinel)
5.2 接受 SENTINEL is-master-down-by-addr 命令
-
目标 Sentinel 收到 SENTINEL 命令后,根据其中的主服务器 IP 和端口号检查主服务器是否已下线;
-
然后向源 Sentinel 返回一个包含三个参数的 Multi Bulk 作为回复;
参数 说明 down_state 返回目标 Sentinel 对主服务器的检查结果,1代表主服务器已下线 leader_runid 可以是 * 符号(用于检测主服务器的下线状态)或目标 Sentinel 的局部领头 Sentinel 的运行 ID(用于选举领头 Sentinel) leader_epoch 目标 Sentinel 的局部领头 Sentinel 的配置纪元,用于选举领头 Sentinel
5.3 接受 SENTINEL is-master-down-by-addr 命令的回复
- 源 Sentinel 统计其他 Sentinel 同意主服务器已下线的数量,达到一定数量后打开主服务器实例结构
flags
属性的 SRI_O_DOWN 标识,标识主服务器已经进入客观下线状态; - 该数量可以在 Sentinel 的
quorum
参数中设置(包括源 Sentinel); - 不同 Sentinel 判断客观下线的条件可能不同;
6. 选举领头 Sentinel
- 当主服务器被判断客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头 Sentinel,并由领头 Sentinel 对下线的主服务器执行故障转移操作;
- Sentinel 系统选举领头 Sentinel 的方法是对 Raft 算法的领头选举方法的实现;
- Redis 选举领头 Sentinel 的规则和方法如下:
7. 故障转移
7.1 选出新的主服务器
- 领头 Sentinel 在从服务器中选出一个状态良好、数据完整的从服务器。选举规则如下:
- 选出来后,发送 SLAVEOF no one 命令,将其设置为主服务器;
- 领头 Sentinel 每秒(正常是每 10 秒)向被升级的从服务器发送 INFO 命令,监控从服务器的
role
属性; - 当服务器的
role
属性从 slave 变成 master 时,表明顺利升级;
7.2 修改从服务器的复制目标
- 领头 Sentinel 通过 SLAVEOF 命令让从服务器复制新的主服务器;
7.3 将旧的主服务器变成从服务器
- 将已下线的主服务器设置为新主服务器的从服务器;