Redis多机模式(二):sentinel哨兵

目录:

  1. Sentinel是什么?有什么用途?
  2. Sentinel环境搭建?
  3. Sentinel的工作流程?如何实现故障检测及故障转移?

1. Sentinel是什么?有什么用途?

Sentinel是Redis的高可用性(high availability)解决方案:

将一个或多个Redis服务器配置成Sentinel哨兵节点,使其成为业务节点的客户端,持续监视主节点及其属下的从节点的状态。如果主机异常下线,则自动进行故障转移,使Redis持续对外提供不间断的读写服务。


2. Sentinel 环境搭建:

启动Sentinel服务器:

./redis-sentinel sentinel.conf

修改 sentinel.conf 配置文件: (关键配置项:sentinel monitor)

# port 26379
port 26379

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
# sentinel monitor <监控主机名> <监控主机IP> <监控主机端口号> <判定客观下线所需选票数>
sentinel monitor mymaster 127.0.0.1 6379 2

# sentinel authpass <master-name> password
# 设置连接主机的登录密码,例如:
sentinel auth-pass mymaster 10086

# sentinel down-after-milliseconds <mastername> <milliseconds>
# 时间内主机没有回复(例如没有回复PING),则判定主机已下线。例如:
sentinel down-after-milliseconds mymaster 30000

# sentinel failover-timeout <master-name> <milliseconds>
# 在failover故障转移开始后,如果规定时间内还没有完成此次故障转移,则Sentinel认为此次failover失败了,例如:
sentinel failover-timeout mymaster 180000

关于 Sentinel 部署的原则:

  1. 至少部署三个Sentinel实例,才能使系统足够的健壮(robust);
  2. 三个Sentinel实例应该被放在不同的计算机主机之上,保证被监控Redis主服务器宕机时不会使Sentinel服务器同时宕机(所有Sentinel实例与Redis主机部署在同一台电脑上就是一个错误的部署方式);
  3. sentinel.conf 配置文件中只需指出要监控的主服务器即可,无需指出从服务器,Sentinel会自动通过 INFO 命令发现从机并与它们建立网络连接;
sentinel monitor mymaster 127.0.0.1 8001 2
# 配置文件中指出主服务器即可,无需指出从服务器信息
  1. 一个经验:sentinel.conf 配置文件中默认的主机名为 mymaster,不要轻易修改它,因为后面的多数配置项都使用的是 mymaster 这个名字,如果改变则后面所有的配置项都需要修改,非常麻烦。
    sentinel monitor mymaster 这个配置必须放在配置文件的前部,如果放在后部,其他配置项会不认识 mymaster 这个服务器而报错,例如:
# 因修改了 sentinel monitor 中指定的主机名字或者将其放在了文件靠后的位置,导致其他配置项找不到主机名而报错:
>>>  'sentinel config-epoch mymaster 0'
No such master with specified name.

Sentinel基础部署方式举例(basic setup):
在这里插入图片描述


3. Sentinel的工作流程:

Sentinel的工作流程如下:

  1. Sentinel服务器启动(初始化及创建连接);
  2. Sentinel与主服务器周期性通信获取主从机的信息并进行故障检测(INFO/10s、PUBLISH/2s、PING/1s)
  3. Sentinel发起并完成故障转移(选举领头Sentinel、选出新主机、主从切换)。

3.1 Sentinel服务器启动(初始化并创建连接):

3.1.1 使用Sentinel专用代码:

如果一个Redis服务器被配置成为了Sentinel模式,那么它所运行的代码与普通的Redis服务器是不相同的。
这是因为Sentinel服务器与普通Redis服务器在功能上有很大区别,例如Sentinel服务器无需支持SET、GET等客户端请求(不支持命令表),也不支持RDB和AOF持久化,所以Sentinel在启动阶段的第一步就是将一部分普通Redis服务器使用的代码替换成Sentinel专用代码。

3.1.2 Sentinel维护监听节点信息:(sentinelRedisInstance)

Sentinel服务器上需要维护其所监听节点的信息,根据 sentinel.conf 配置文件中的配置信息,创建所监听服务器的结构体。
一个Sentinel服务器上需要每个它所监听的节点创建一个 sentinelRedisInstance 结构(包括监听的主节点及其属下的从节点)。

sentinel.c/sentinelRedisInstance 结构体的内容如下:

typedef struct sentinelRedisInstance {
	int				flags;				//标识实例类型及状态,如:SRI_MASTER; SRI_SLAVE; SRI_S_DOWN; SRI_O_DOWN;
	char			*name;				//主服务器名字,在sentinel.conf中配置,格式为ip:port,如“127.0.0.1:9001
	char			*runid;				//运行ID
	uint64t			config_epoch;		//纪元
	sentinelAddr	*addr;				//实例的网络地址,包含IP和端口号
	
	mstime_t 		down_after_period;	//判断主观下线所需超时时间,由down_after_milliseconds配置
	int				quorum;				//判断客观下线所需票数,由<quorum>配置
	mstimet			failover_timeout;	//故障迁移最大时限,由failover-timeout配置
	dict			*slaves;			//slaves for this master instance. 这个主机属下的从机

	//当此结构体表示的是一个从机时,以下三个成员用于表示通过执行 INF0 命令所获得的信息:
	char	*slave_master_host;			/* Master host as reported by INFO */
	int		slave_master_port;			/* Master port as reported by INFO */
	int		slave_master_link_status;	/* Master link status as reported by INFO */

	//通过PUBLISH消息,Sentinel可以知道正在监听这台主机的其他Sentinel服务器
	dict	*sentinels;					/* Other sentinels monitoring the save master. */
} sentinelRedisInstance;

typedef struct sentinelAddr {
	char 	*ip;
	int 	port;
} sentinelAddr;

3.1.3 Sentinel创建连向监听节点的网络连接:

Sentinel将会成为监听节点的客户端,向监听节点发送命令并从回复中获取主机状态信息。
Sentinel与监听主机之间的连接有两种:一个是命令连接,一个是订阅连接。


3.2 Sentinel与主服务器周期性通信(INFO、PUBLISH、PING):

3.2.1 INFO命令:Sentinel获取主服务器及其属下从服务器的状态信息(10s)

Sentinel默认以每十秒一次的频率,向被监视主机发送 INFO 命令,以获取主机及其属下从机的状态信息。

在主机上执行 INFO 命令所获取的从机信息如下:

127.0.0.1:8001> INFO
#Replication
role:master
connected_slaves:2
slaveO:ip=127.0.0.1,port=8002,state=online,offset=889980,1a8=1    <=== 从机信息
slave1:ip=127.0.0.1,port=8003, state=online,offset-889994,1ag=1	  <=== 从机信息
naster_ replid:0e32576c470081417e98b91eb5cbf93aa1e38b3b
naster_replid2:0000000000000000000000000000000000000000
master_repl_offset:889994
second_repl__offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:889994

sentinelRedisInstance 结构中保存的信息如下:

typedef struct sentinelRedisInstance [
	dict	slaves;						//slaves for this master instance.这个主机属下的从机
	
	//当此结构体表示的是一个从机时,以下三个成员用于表示通过执行 INF0 命令所获得的信息:
	char	*slave_master_host;			//master host as reported by INFO
	int		slave_master_port;			//master port as reported by INFO
	int		slave_master_link_status;	//master link status as reported by INFO
} sentinelKedisInstance;

3.2.2 PUBLISH命令: Sentinel向主从服务器发送消息(2s)

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

Sentinel默认以每两秒一次的频率,向所监听的主服务器及从服务器发送 PUBLISH 命令。
其中,“s_” 开头表示Sentinel本身信息; “m_” 开头表示主机信息。

Sentinel 通过订阅连接,从 __sentinel__:hello 接收信息,通过发布频道信息声明自己的存在,通过接收频道消息获知其他Sentinel的存在。以此达到监视同一个主服务器的Sentinel可以自动发现的效果。(Sentinel之间只创建命令连接不创建订阅连接)

typedef struct sentinelRedisInstance {
	dict	*sentinels;		//Other sentinels monitoring the save master.
} sentinelRedisInstance;

3.2.3 PING命令: Sentinel故障检测(1s)

Sentinel默认会以每一秒一次的频率向所有与它连接的实例发送 PING 命令,包括 主服务器、从服务器、其他Sentinel,若在 down-after-milliseconds 时间内目标主机连续向Sentinel返回无效回复,或超时未回复,则Sentinel判定目标主机进入主观下线状态。

具体故障检测的过程见下文。

3.3 Sentinel的故障检测与故障转移:

3.3.1 故障检测:

故障检测是通过PING命令实现:

(1) 主观下线:(PING -> down-after-milliseconds)

Sentinel 默认以每一秒一次的频率向主服务器发送 PING 命令,如果目标主机在 down-after-milliseconds 毫秒内,连续向Sentinel返回无效回复,或超时未回复,则Sentinel更新目标主机所对应的实例状态为:sentinelRedisInstance->flags = SRI_S_DOWN,表明目标主机已经进入 主观下线 状态。

typedef struct sentinelRedisInstance {
	int			flags;				//SRI_MASTER/ SRI_SLAVE/ SRI_S_DOWN/ SRI_O_DOWN
	mstime_t	down_after_period;	// = down-after-milliseconds
} sentinelRedisInstance;

注:

  1. down-after-millisecondssentinel.conf 文件中的配置项,表示判断目标主机进入主观下线的条件:
# sentinel down-after-milliseconds <master-name> <milliseconds>
# Number of milliseconds the master (or any attached replica or sentinel) should 
# be unreachable in order to consider it in S_DOWN state.

sentinel down-after-milliseconds mymaster 30000
  1. sentinel.conf 中配置的 down-after-milliseconds 不仅会被用作Sentinel判断主服务器主观下线的条件,还会成为判断此主机属下的所有从服务的主观下线条件;
  2. 多个Sentinel设置的 down-after-milliseconds 的值可能不同。
(2) 客观下线: (is-master-down-by-addr)
① 发送 is-master-down-by-addr 命令:

当某个Sentinel判断一个主服务器主观下线后,就会发送命令向其他Sentinel询问此主机是否真的下线。
例如:

# SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
SENTINEL is-master-dowm-by-addr 127.0.0.1 8001 0 *

其中,< ip > 和 < port > 用于指示主观下线的主机IP和端口号;
< current_epoch > 和 < runid > 用于后续的选举领头Sentinel,如果is-master-down-by-addr 命令只是用于询问,则二者的值为"0" 和 “*”。

② 接收并回复 is-master-down-by-addr 命令:

当Sentinel收到 is-master-down-by-addr 命令后,解析并回复(解析IP和端口号得到目标主机信息),如果Sentinel维护的sentinelRedisInstance 实例表示目标主机已下线,则回复:

# SENTINEL is-master-down-by-addr <down_state> <leader_runid> <leadere_epoch> 
SENTINEL is-master-down-by-addr 1 * 0

回复内容的3个字段:

<down_state>	:	1 表示 下线,0 表示 未下线
<leader_runid>	:	用于选举领头Sentinel
<leader_epoch>	:	用于选举领头Sentinel
③ 接收 is-master-down-by-addr 命令的回复:

如果判断目标主机已下线的Sentinel数量超过 < quorum > 阈值,则Sentinel 更新目标主机状态为客观下线:

sentinelRedisInstance->flags = SRI_O_DOWN;

3.3.2 故障转移:

当Sentinel检测到某主机已进入 客观下线 状态,则发起对目标主机的故障转移(哨兵模式下的故障转移是由Sentinel发起的,而集群模式下的故障转移则是由下线主机的从机发起的),步骤如下:

(1) 选举领头Sentinel:

在确认主服务器已进入下线状态之后,Sentinel会再次发送is-master-down-by-addr命令,这次会携带自己的运行ID和纪元值,要求收到此命令的Sentinel投票给自己:

SENTINEL is-master-down-by-addr 1 e93f9e39fm9ef9emd93k93kdk9d 0

Sentinel收到投票请求后,如果在本次纪元内还有投票机会,则回复 is-master-down-by-addr,将回复中 < runid > 置为收到的一个投票请求的Sentinel 的运行ID。
获得选票超半数的Sentinel会成为领头Sentinel。

(2) Sentinel从下线主机属下的从机中选出一个升级为新的主机:

过滤规则:
① 删除下线状态从机 > ② 删除5秒内未回复Sentinel的INFO消息的从机 >
③ 删除与断开时长超down-after-milliseconds*10的从机 >
④ 从机优先级排序(选最高) > ⑤ 复制偏移量(offset)(选最大)>⑥运行ID(选最小)

待选出新的主机后,领头Sentinel向被选出的从机发出SLAVEOF no one 命令,并以每秒一次的频率向其发送INFO命令查看其是否已从slave切换为master(正常情况下INFO命令的发送频率是每一秒一次)。

(3) Sentinel向下线主机属下的其他所有从机发送新的复制命令,让它们成为新主机的从机;

在新的主机完成从slave到master的切换后,领头Sentinel向其他slave发送SLAVEOF命令,使它们成为新主机的从机。

(4) Sentinel继续监视下线主机,当其重新上线时,使其成为新主机的从机。

参考内容:

《Redis设计与实现》第三部分 第16章 Sentinel
Redis官方文档: https://redis.io/topics/sentinel

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值