Redis设计与实现——Redis Sentinel(哨兵)

概念

由一个或者多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器。并在被监视的主服务器进入下线状态时,自动将下线的主服务器属下的某个从服务器升级为新的主服务器,并由这个新的主服务代替已下线的主服务器继续处理命令请求。如果已下线的前主服务回复上线,则会被降级这新的主服务器的从服务器。

一个Sentinel可以监视多个主服务器,一个主服务器也可以被多个Sentinel监视。

Sentinel的初始化

  1. 初始化服务器:Sentinel本质上是一个特殊模式下得Redis服务器,所以第一步就是初始化一个普通Redis服务器,但Setinel初始化过程中不加载数据库等。
  2. 将普通Redis服务器使用的代码替换成Sentinel专用代码:如端口号、命令表
  3. 初始化Sentinel状态
struct sentinelState{
	//当前纪元,用于实现故障转移
	unit64_t current_epoch;
	//保存所有被sentinel监视的主服务器,是一个字典,
	//字典的键时主服务器的名字,字典的值时一个指向SentinelRedisInstance结构的指针
	dict *masters;
	//是否进入了TILT模式
	int tilt;
	//目前正在执行的脚本的数量
	int running_scripts;
	//进入TILT模式的时间
	mstime_t tilt_start_time;
	//最后一次执行时间处理器的时间
	mstime_t previous_time;
	//一个FIFO队列,包含了所有需要执行的用户脚本
}sentinel
  1. 根据配置文件,初始化Sentinel的监视主服务器列表
typeof struct SentinelRedisInstance{
	//标识值,记录了实例的类型,以及该实例的当前状态
	int flags;
	//实例的名字
	//主服务器:由用户在配置文件中设置
	//从服务器与Sentinel:ip:port
	char *name;
	//实例的运行ID
	char *runid;
	//配置纪元,用于实现故障转移
	unit64_t config_epoch;
	//实例的地址
	sentinelAddr *addr;
	//SENTINEL down_after_milliseconds选项设置的值
	//表示实例多少毫秒内没有响应会被判定为主观下线
	mstime_t down_after_milliseconds;
	//SENTINEL monitor <master-name> <IP> <port> <quorum>选项中的quorum值
	//判断实例为客观下线时所需要满足的投票数量
	int quorum;
	//SENTINEL parallel-syncs <master-name> <number> 选项的值
	//只执行故障转移操作时,可同时对新的主服务器进行同步的从服务器数量
	int parallel_syncs;
	//SENTINEL failover_timeout <master-name> <ms> 选项的值
	//刷新故障迁移状态的最大时限
	mstime_t failover_timeout;
	...
	
}SentinelRedisInstance

在这里插入图片描述
在这里插入图片描述

  1. 创建连向主服务器的网络连接
    Sentinel会创建两个连向主服务器的异步网络连接:
    命令连接:用于向主服务器发送命令,并接收命令回复;
    订阅连接:订阅主服务器的_sentinel_:hello频道

获取主服务器信息

以上初始化完成后,Sentinel默认每10s一次的频率,通过命令连接向主服务器发送INFO命令来获取主服务器的当前信息。
在这里插入图片描述
如图,获取的数据有两方面
一个是关于主服务器自身的信息,用于对主服务器的实例结构进行更新;
一个是关于从服务器的信息,可用于更新主服务器实例结构的slaves字典。
------>如果从服务器信息已经存在主服务器,那么更新从服务器数据;如果不存在,就创建新的实例结构。并为新的实例结构创建命令连接和订阅连接!
在这里插入图片描述
注:从服务器的name属性值是Sentinel根据从服务器的IP地址和端口号自动设置的。

获取从服务器

在默认情况下,Sentinel会以每10s一次的频率通过命令连接向从服务器发送INFO命令。获得INFO命令回复并提取信息对从服务器的实例结构进行更新。
在这里插入图片描述

向主服务器和从服务器发送信息

默认情况下,Sentinel会以每2s的一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送一下格式的命令

PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

参数说明
在这里插入图片描述

接收来自主服务器和从服务器的频道信息

当Sentinel与一个主服务器或者从服务器建立订阅连接后,Sentinel就会通过订阅连接向服务器发送:

SUBSCRIB __sentinel__:hello

此时,Sentinel对__sentinel__:hello的订阅会持续到Sentinel与服务器的连接断开为止
在这里插入图片描述
在这里插入图片描述

更新sentinels字典

Sentinel为主服务器创建的实例结构中的sentinels字典保存了除自身以外所有的同样监视这个主服务器的其他Sentinel信息。
当Sentinel收到其他Sentinel发送的信息时,会提取出其信息。信息包含参数:
源Sentinel的IP地址、端口号、运行ID和配置纪元;以及源Sentinel正在监视的主服务器名字、IP地址、端口号和配置纪元这八个参数。

如果源Sentinel的实例结构存在,就对源Sentinel的实例结构进行更新;如果不存在,就创建新的实例结构,并添加到sentinels字典里。
在这里插入图片描述

创建连向其他Sentinel的命令连接

当Sentinel通过频道信息发现一个新的Sentinel时,不仅会为新Sentinel在sentinels字典中创建相应的实例结构,还会创建一个连向新Sentinel的命令连接。而新Sentinel同样会创建连向这个Sentinel的命令连接。
最终所有监视同一主服务器的Sentinel都互相形成命令连接。

检测主观下线状态

Sentinel会每隔1s向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他sentinel)发送PING命令。

回复:

有效回复 : +PONG / -LOADING / -MASTERDOWN 
无效回复:  除以上三种回复外的其他回复

根据设置的down_after_milliseconds所设置的时间长,如果在规定的毫秒内,向Sentinel回复的都是无效回复,那么Sentinel会认为这个实例已经进入主观下线状态,修改对应实例结构中的flag属性,打开其SRI_S_DOWN标识。
在这里插入图片描述
如图,master被认为主观下线。

检查客观下线状态

  1. 当Sentinel将一个主服务器判断为主观下线后,会向其他同样监视这个主服务器的sentinel进行询问
  2. 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; * 表示命令仅用于检测主服务器的客观下线;而运行ID用于选取领头Sentinel。

SENTINEL is_master_down_by_addr 127.0.0.1 6379 0 *
  1. 接收源Sentinel发送的 SENTINEL is_master_down_by_addr 命令
    目标sentinel接收到源Sentinel发送的 SENTINEL is_master_down_by_addr 命令时,会分析并提取出请求命令中包含的参数,根据其中的主服务器IP和端口号,检查主服务器是否已下线,然后向源Sentinel返回包含三个参数的Multi Bulk回复。
1) <down_state>
2) <leader_runid>
3) <leader_epoch>

//down_state: 返回目标sentinel对主服务器的检查结果: 1代表主服务器已下线; 0代表主服务器未下线
//leader_runid: * 代表命令仅用于检测服务器的下线状态;目标sentinel的局部领头Sentinel的运行ID 用于选举领头Sentinel;
//leader_runid: 仅在leader_runid不为*时有效,表示目标sentinel的局部领头sentinel的配置纪元,用于选举领头领头sentinel。

1) 1
2) *
3) 0
//表示该sentinel同意主服务器已下线
  1. 接收SENTINEL is_master_down_by_addr的命令回复
    sentinel将统计其他sentinel同意主服务器已下线的数量,如果这个数量到达配置指定的判断客观下线所需数量(quorum参数值)时,就认为这个主服务器已进入客观下线状态,将实例结构的flags属性的SRI_O_DOWN标识打开。
    在这里插入图片描述

选取领头Sentinel

选取规则:
· 所有在线的Sentinel都有被选为领头Sentinel的资格
· 每次进行领头Sentinel选举之后,不论选举是否成功,所有Sentinel的配置纪元的值都会自增一次
· 在一个配置纪元里面, 所有Sentinel都有一次将某个Sentinel设置为局部领头Sentinel的机会,并且局部领头一旦设置,在这个配置纪元里面就不能再更改。
· 每个发现主服务器进入客观下线的Sentinel都会要求其他Sentinel将自己设置为局部领头Sentinel。
· 当一个Sentinel(源Sentinel)向另一个Sentinel(目标Sentinel)发送SENTINEL ismaster-down-by-addr命令,并且命令中的runid参数不是*符号而是源Sentinel的运行ID时,这表示源Sentinel要求目标Sentinel将前者设置为后者的局部领头Sentinel
· Sentinel设置局部领头Sentinel的规则是先到先得
· 目标Sentinel在接收到SENTINEL is-master-down-by-addr命令之后,将向源Sentinel返回 一条命令回复,回复中的leader_runid参数和leader_epoch参数分别记录了目标Sentinel的局部领头Sentinel的运行ID和配置纪元
· 源Sentinel在接收到目标Sentinel返回的命令回复之后,会检查回复中leader_epoch参数 的值和自己的配置纪元是否相同,如果相同的话,那么源Sentinel继续取出回复中的 leader_runid参数, 如果leader_runid参数的值和源Sentinel的运行ID一致,那么表示目标 Sentinel将源Sentinel设置成了局部领头Sentinel
· 如果有某个Sentinel被半数以上的Sentinel设置成了局部领头Sentinel,那么这个Sentinel成 为领头Sentinel。
· 因为领头Sentinel的产生需要半数以上Sentinel的支持,并且每个Sentinel在每个配置纪元里面只能设置一次局部领头Sentinel,所以在一个配置纪元里面,只会出现一个领头 Sentinel
· 如果在给定时限内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将在一段时间之后再次进行选举,直到选出领头Sentinel为止

故障转移

由领头Sentinel对已下线的主服务器进行故障转移操作

  1. 在已下线的主服务器属下的从服务器中选出新的主服务器
1.删除列表中所有处于下线或者断线的从服务器
2.删除列表中最近5s内没有回复过领头Sentinel的INFO命令的从服务器。
3.删除所有与已下线主服务器连接断开超过down-after-milliseconds * 10ms的从服务器。
4.在剩余的从服务器中,选取优先级最高的服务器为新主服务器。
5.优先级最高的从服务器有多个时,选取其偏移量最大的从服务器。
6.如果上述结果仍有多个服务器, 则根据运行ID进行排序,选取运行ID最小的服务器。

领头Sentinel向选出从服务器发送SLAVEOF no one命令,且会每隔1s的频率向被升级的从服务器发送INFO命令,观察其role值是否从slave变成了master

  1. 修改其他从服务器的复制目标
    领头Sentinel向其他从服务器发送SLAVEOF <新主服务器IP> <新主服务器port>,让他们复制新的主服务器。
  2. 旧主服务器变为从服务器
    在已下线的主服务重新上线时,领头Sentinel就会发送SLAVEOF命令,使其变成新的主服务器的从服务器。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值