redis 哨兵_深入理解Redis哨兵集群

一、背景

在前面一篇文章《深入理解Redis主从复制》中,我们介绍过Redis的主从架构,回顾一下主从架构,我们都知道,主从架构可以实现读写分离,降低主节点的写入压力,但是仍然存在着这样一个天然缺陷,那就是主节点存在单点故障的可能,也就是主从架构可以满足高性能的要求,但不能满足高可用的要求。不能满足的原因就是:如果主节点crash掉了,那么整个主从集群将无法写入新数据。

针对主从架构中,主结点crash的情况,那么Redis提供了什么样办法来作为高可用的解决方案呢?总的来说,有两种:哨兵集群和Cluster集群,关于Cluster集群,由于篇幅的限制,我们后面再专门撰文来研讨。今天我们主要介绍一下Redis高可用架构中的哨兵集群。

二、核心原理

什么叫哨兵集群呢?哨兵,我们的理解通常就是站岗、放哨的意思,没错,Redis的哨兵的主要职责就是包含了这些。

下面,我们具体的来聊聊Redis哨兵都能干什么呢?那么我们先来回顾一下主从架构存在的单点故障问题,以及要解决如何主节点单点故障,哨兵该干哪些事情?我们就大概可以推断出哨兵的作用了。如下图所示:

bffef4bec0ce9f31b7eb6babd616aa20.png

由上图一眼就可以看出,如果主节点crash掉了,那么整个主从集群将无法提供写入功能。

那么问题来了,要让整个集群在主节点挂掉以后,还能提供写入功能,怎么办?那么哨兵集群技术就是把从节点提升为主节点来达成集群写入的。那么哨兵要做哪些事情呢?

(1)、分别监控主节点及所有从节点的运行状态,我们称为“监控”;

(2)、当主节点crash掉了,还要将从节点提升为主节点,这个过程叫,我们称为“选主”;

(3)、选完主之后呢,还得通知客户端往新主节点写入数据,这个过程叫,我们称为“通知”;

(4)、当主从集群发生了主节点故障,哨兵要切换主节点的时候,还可以通知技术人员,我们称为“预警”。

(5)、哨兵通常也以集群的方式部署(因为单个哨兵也同样存在单点故障),因此,哨兵之间还需要保持通信。

以上就是整个哨兵集群要做的最主要的事情,下面我们再看看哨兵集群的一种最常见的部署架构图,如下所示:

24755ae5a26707a612ae2d46407eb77b.png

这里我先介绍一下哨兵,其实哨兵也是一个Redis实例,如果要以哨兵的方式启动redis实例,我们可以使用下面的命令:

sentinel monitor

看起来,部署一个哨兵是不是很简单,你可能会觉得奇怪?根据刚才我们上面说的哨兵集群的功能里,我们会产生这样两个问题:

问题1:哨兵是如何相互之间自动组成集群的?

我们都知道,Redis其实为我们提供了发布/订阅(pub/sub)机制,每一个redis主节点起来的时候,它都有一个频道叫"__sentinel__:hello", 那么哨兵实例启动后会订阅这个频道,并在这个频道发布消息,说我订阅了这个频道,并且我还可以知道有哪些其它人也订阅了这个频道。这样的话,所有哨兵就是通过发布/订阅机制巧妙的完成了自动组成集群。

为了更加直观,我们画一个图来描述,如下所示:

72f710c191241abb6df084ebc8f6ca63.png

问题2:哨兵是如何跟从节点进行通信的呢?

哨兵实例启动后,会先主节点发送info命令,然后主库把从节点列表返回给哨兵,然后哨兵再和从节点列表中的每一个从节点建立链接,具体如下图所示:

5ef887f3fa38f48e09fac790d38463cc.png

好啦,集群搭建起来了之后,哨兵开始工作啦。。。

接下来的问题是:如果集群中的主节点crash掉了,哨兵集群是如何判断出主节点到底是否真的已经crash掉了呢?

这里我们先介绍一下两个概念:“主观下线”和“客观下线”。

主观下线:简单的来说,就是哨兵对大家说:“我觉得主节点已经crash掉了”,这叫“主观下线”。

客观下线:细心的你一定已经发现前面启动redis哨兵实例的时候,我们输入了一个参数叫quorum,没错,通常我们设置为大于哨兵数量1/2的值,这个值就是仲裁票数,什么意思呢?就是说:对于任何一哨兵来讲,如果大多数(大于或等于quorum)的哨兵都把自己主观下线的观点告诉了这个哨兵(包含他自己的那一票),那么这个哨兵就可以认为这个主节点已经“客观下线”了。

那么这个过程是如何完成的呢?

上面我们已经提到过,哨兵已对完成了对所有主从节点的运行状态的监控,哨兵通过心跳检测来判断主节点是否已经crash,这个就是哨兵判断主观下线的依据所在。

任何一个实例只要自身判断主库“主观下线”后,就会给其他实例发送 is-master-down-by-addr 命令。接着,其他实例会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。每一个哨兵关于“主观下线”的这一票,要么投给自己,要么投给别的哨兵,能且只能投一次票。投完之后,就会拒绝所有其它的投票请求(包括自己)。

对于某个哨兵实例来说,它率先拿到了达到quorum数量的票数之后,这个哨兵就觉得主节点已经“客观下线”。

OK,既然某个哨兵已经判断主节点“客观下线”,那么接下来的事情应该是:哨兵要开始从节点列表中确定新的主节点了,也就是“选主”的过程,那么新的主节点该如何确定呢?

具体操作来说,主要是通过给所有的从节点打分来确定,得分最高的将成为新的主节点,那么打分的依据与步骤是什么样的呢?具体来说,有如下三步:

1、优先级高的最分最高;

Redis为我们提供了一个优先级配置的参数:replica-priority 100,它的默认值是100。当 master 不能正常工作的时候,哨兵会从节点列表中选出一个新的主节点,这个值越小,就越会被优先选中,但是如果是0,那是意味着这个从节点不可能被选中。默认优先级为100。

2、和原主节点同步程序最接近的得分最高;

在前面一文《深入理解Redis主从复制》中,已经提到,原主节点有一个值叫master_repl_offset,而所有从节点都维护了自己的一值slave_repl_offset的值,他们都是单调增大的。且满足master_repl_offset>=slave_repl_offset的条件。slave_repl_offset的值越大,我们认为这个从节点的数据库越接近主节点。

3、ID号最小的从节点得分最高。

另外,每一个redis实例启动的时候,系统都会为它分配一个id,如果前面的两轮得分都完成一样的话,那么将会由所有从库中ID号最小的那个从节点来担任新的主节点。

新的问题是,大家已经选出了新的主节点,我们可以称它为“新主”,哨兵那么多,到底该由谁来负责执行“新主”提升的操作呢?这个去执行“新主”提升操作的哨兵,我们称为哨兵Leader。

要担任这个Leader需要同时满足2个条件:

1、客观下线投票环节,得到的票数在大于等于quorum的配置;

2、客观下线投票环节,达到的票数要大于等于1/2的哨兵数量。

最后会由同时满足这2个条件的那个哨兵将作为哨兵Leader去执行“新主”的切换工作,并且通知客户端,主节点已经更换,具体方式是将“新主”的ip和port推送给客户端。

最后,我们再来总结一下整个过程:

(1)、哨兵集群监控主从集群;

(2)、哨兵集群感知到主节点已经crash;

(3)、哨兵集群找出适合提升为“新主”的从节点;

(4)、哨兵内部选出哨兵Leader去执行“新主”的提升;

(5)、哨兵Leader执行“新主”的提升操作并将“新主”的信息通知给所有的客户端;

(6)、主从集群完成自动的故障恢复,重新可以正常接受客户端的写入请求。

三、常见问题

第二节中,我们已经介绍完了整个哨兵集群的核心原理,其实上面的步骤中还存在着一些问题,下面我们针对这些问题一个个来分析(以上面共3个哨兵、quorum值为2的情况为例):

问题1:如果3个哨兵中,有一个哨兵挂了,剩下的两个哨兵,剩下的两个哨兵在“主观下线”投票时,都只把票投给了自己,这个时候,所有的哨兵既达不到quorum值,也不有办法超过哨兵总数的1/2?哨兵Leader还能选出来 吗?

为了解决这种各个哨兵的得票数都不能满足要求的情况,redis做了如下的设计:

1、每个哨兵在检测主节点的心跳检测的时候,都维护了一个定时器,通常来说,在100ms左右,然而每一个哨兵真正执行的时候,会在这个100ms的基础之上,再增加一个det值(一个随机的毫秒数),这样的话,不同的哨兵之间就可以把时间检测的时间进行错开。这样,就很少会出现同时把票投给了自己,而拒绝投给别人的情况;

2、有一种极端情况,就是投票的过程中,出现了网络延迟或拥塞,还是有可能出现各自同时把票投给自己的情况存在。那么针对这种情况,如果第一轮投票失败,投票时间如果超过一定的时间限制,比如说达到了故障自动转移时间的2倍的话,那么哨兵集群会再重新开始新一轮的投票,进一步降低这种可能性。

问题2:在主节点crash掉之后,“新主”切换完成之前,客户端的写入请求怎么办?

目前Redis本身,并不能解决这个问题,在“新主”切换完成之前,整个集群是没有办法接受写入请求的。如果业务允许写入延迟,可以考虑在客户端增加MQ来缓存写入请求。

问题3:由于“新主”跟原来的主节点之间,数据的完整度上,仍然存在着一定的差距,那“新主”切换完成之后,是有可能导致一定的数据丢失的。

问题4:前面的客观下线的判断过程,其实仍然是存在误判的可能,比如说:网络出现了故障,所有的从节点和哨兵集群可以正常通信,而原来的主节点还活着(只是由于网络故障与哨兵以及从节点之间无法通信了),这个时候呢,会选出一个从节点当成新的主节点。那么问题就来了,这个时候,实际上有两个主节点存活。恰好有一部分客户端处于跟原主节点同一个网络分区。这种情况,我们称为:集群脑裂问题。这种情况下,会有一些客户端继续将数据写入原来的主节点。

为了降低这种情况的影响,Redis提供了两个参数:min-replicas-to-write和min-replicas-max-lag来进行配置,具体含义,请参见《深入理解Redis主从复制》,目的就是为了让集群脑裂的原主节点拒绝那些跟它处于同一个网络分析的客户端的写入请求。

四、常见部署架构

通常情况下,我们一般不会像上面去单独部署哨兵集群,常见的部署架构图如下:

50803f83204ce90bd66e4ce076d77413.png

这种部署方式的好处是:

(1)、可以节约机器资源;

(2)、降低网络故障影响“新主”切换的过程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值