redis------第八天学习笔记(哨兵集群:哨兵挂了,主从库还可以切换吗?)

上次我们学习了哨兵机制,他可以实现主从库的自动切换。通过部署多个实例,就形成了一个哨兵集群。哨兵集群中的多个实例共同判断,可以降低对主库下线的误判率。但是我们还要考虑一个事情:如果有哨兵实例在运行时发生了故障,主从库还能正常切换吗?

实际上,一旦多个实例组成了哨兵集群,即使有哨兵实例出现故障挂掉了,其他哨兵还能继续协作完成主从库切换的工作,包括判断主库是不是处于下线状态,选择新主库,以及通知从库和客户端。

如果你部署过哨兵集群的话就会知道,在配置哨兵的信息时,我们只需用到下面的这个配置项,设置主库的IP和端口,并没有配置其他哨兵的连接信息。

sentinel monitor <master-name> <ip> <redis-port> <quorum> 

这些哨兵实例既然都不知道彼此的地址,又是怎么组成集群的吗?要弄明白这个问题,我们需要学习一下哨兵集群的组成和运行机制了。

基于pub/sub机制的哨兵集群组成:

哨兵实例之间可以相互发现,要归功于Redis提供的pub/sub机制,也就是发布/订阅机制。
哨兵只要和主库建立起来了连接,就可以在主库上发布消息了,比如发布它自己连接信息(IP和端口)。同时,它也可以从主库上订阅信息,获得其他哨兵发布的连接信息。当多个哨兵实例都在主库上做了发布和订阅后,它们之间就能知道彼此的IP地址和端口。

除了哨兵实例,我们自己编写的应用程序也可以通过Redis进行消息的发布和订阅。所以,为了区分不同应用的消息,redis会以频道的形式,对这些消息进行分门别类的管理。所谓的频道,实际上就是消息的类别。当消息类别相同时,他们就属于同一个频道。反之,就属于不同的频道。只有订阅了同一个频道的应用,才能通过发布的消息进行信息交换。

在主从集群中,主库上有一个名为"_ sentinel :hello"的频道,不同哨兵就是通过它来相互发现,实现互通信息。
可依举个例子,具体说明一下。再下图中,哨兵1把自己的IP(172.16.19.3)和端口(26579)发布到"
sentinel _:hello"频道上,哨兵2和哨兵3订阅了该频道。那么此时,哨兵2和哨兵3就可以从这个频道直接获取哨兵1的IP地址和端口号。
然后哨兵2和哨兵3可以和哨兵1建立网络连接,这样一来,哨兵集群就形成了。它们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事进行判断和协商。
在这里插入图片描述
哨兵除了彼此之间建立起连接形成集群外,还需要和从库建立连接。这是因为,在哨兵的监控任务中,他需要对主从库都进行心跳判断,而且在主从库切换完成后,他还需要通知从库,让他们和新主库进行同。

那么,哨兵是如何知道从库的IP和端口的呢?

这是由哨兵向主库发送INFO命令完成的。就像下图只是,哨兵2给主库发送INFO命令,主库接收到这个命令后,就会把从库列表返回给哨兵。接着,哨兵就可以根据从库列表的连接信息,和每个从库建立连接,并在这个连接上持续的对从库进行监控。哨兵1和哨兵3可以用过相同的法和从库建立连接。
在这里插入图片描述
你看,通过pub/sub机制,哨兵之间可以组成集群,同时,哨兵又通过INFO命令,获得了从库连接信息,也能和从库建立连接,并进行监控了。

但是,哨兵不能只和主、从库连接。因为,主从库切换后,客户端也需要知道新主库的连接信息,才能像新主库发送请求操作。所以,哨兵还需要完成把新主库的信息告诉客户端这个任务。

而且,在实际使用哨兵时,我们有时会遇到这样的问题:如何在客户端通过监控了解哨兵进行主从切换的过程呢?比如说,主从切换到哪一步了?这其实就是要求,客户端能够获取到哨兵集群在监控、选主、切换这个过程中发生的各个事件。
此时我们仍然可以依赖pub/sub机制,来帮我们完成哨兵和客户端间的信息同步。

基于pub/sub机制的客户端事件通知:

从本质上说,哨兵就是一个运行在特定模式下的Redis实例,只不过它并不服务请求操作,只是完成监控、选主和通知的任务。所以,每个哨兵实例也提供sub/pub机制,客户端可以从哨兵订阅信息。哨兵提供的消息订阅频道有很多,不同频道包含了主库从库切换过程中的不同关键时间。

频道有这么多,一下子全部学习容易丢失重点,为了减轻学习压力,我把重要的频道汇总在一起,设计几个关键事件,包括主库下线判断,新主库选定、从库重新配置。
在这里插入图片描述
知道了这些频道之后,你就可以让客户端从哨兵这里订阅消息了。具体的步骤是客户端读取哨兵的配置文件后,可以获得哨兵的地址和端口,和哨兵建立网络连接。然后,我们可以再客户端执行订阅命令,来获取不同的事件消息。

举个例子:你可以执行以下命令,来订阅“所有实例进入客观下线状态的事件”:

SUBSCRIBE +odwn

也可以执行下面的命令,订阅所有的事件:

PSUBSCRIBE *

当哨兵把新主库选择出来后,客户端就会看到下面的switch-master事件。这个事件表示主库已经切换了,新主库的IP地址和端口信息已经有了。这个时候,客户端就可以用这里的新主库地址和端口进行通信。

 switch-master <master name> <oldip> <oldport> <newip> <newport>

有了这些事件通知,客户端不仅可以再主从切换后得到新主库的连接信息,还可以监控到主从库切换过程中发生的各个重要事件。这样,客户端就可以知道主动切换进行到哪一步了,有利于了解切换速度。

好了,有了pub/sub机制,哨兵和哨兵之间、哨兵和从库之间、哨兵个客户端之间就都能建立起连接了,再加上我们之前介绍的主库下线判断和选主依据,哨兵集群的监控、选主和通知三个任务就基本可以正常工作了。不过,我们还需要考虑一个问题:主库故障后,哨兵集群有多个实例,那怎么确认由哪个哨兵来进行实际的主从切换呢?

有由哪个哨兵执行主从切换?

确定由哪个哨兵执行主从切换的过程,和主库“客观下线”的判断过程类似,也是一个“投票仲裁”的过程。再具体了解这个过程前,我们再来看下,判断“客观下线”的仲裁过程。

哨兵集群要判断“主管下线”,需要有一定数量的实例都认为该库已经“主观下线”了。在之前我们介绍过判断“客户下线”的原则,接下来我们在介绍下具体的判断过程。

任何一个实例只要自身判断主库“主管下线”后,就会给其他实例发送is-master-down-by-addr命令。接着,其他实例会根据自己和主库的连接情况,做出Y或N的响应,Y相当于赞成、N想当与反对票。
在这里插入图片描述
一个哨兵获得了仲裁所需的赞成票数后,就可以标记主库为“客观下线”。这个所需的赞成票数是通过哨配置文件中的quorun配置设定的。例如:现在有5个哨兵,quorum配置的是3,那么一个哨兵需要配3张赞成票,就可以标记主库为“客观下线了。这3张赞成票包括哨兵自己的一张赞成票和另外两个哨兵的赞成票。”

此时,这个哨兵就可以再给其他哨兵发送命令、表明希望由自己来执行主从切换,并让所有其他哨兵进行投票。这个投票过程称为“Leader选举。因为最后执行主从切换的哨兵称为Leader”,投票过程就是确定leader。

在投票过程中,任何一个想称为Leader的哨兵,要满足两个条件:
第一:拿到半数以上的赞成票。
第二:拿的票数同时还需要大于等于哨兵配置文件中的quorum值,以3个哨兵为例,假设此时的quorum设置2,那么任何一个想成为Leader的哨兵只要拿到两张赞成票,就可以了。
这么说你可能还不太好理解,用一张图片可以解释一下选举过程。
在这里插入图片描述

  • T1时刻,S1判断主库为“客观下线”,他想成为Leader,就先给自己投张赞成票,然后分别向S2和S3发送命令。表示要成为leader
  • 在T2时刻,S3判断主库为“客观下线”,它也想成为Leader,所以也先给自己投一张赞成票,在分别像S1和S2发送命令,表示要成为Leader.
  • 在T3时刻,S1收到了S3的Leader投票请求。因为S1已经给自己投了一票Y,所以它不能再给其他哨兵赞成票了,所以S1回复N表示他不同意。同时。S2收到了T2时S3发送的Leader投票请求。因为S2之前没投过票,他会给第一个向他发送投票请求的哨兵回复Y。给后续在发送投票请求的哨兵回复N,所以,再T3时,S2回复S3,同意S3称为Leader.
  • 在T4时刻,S2才收到T1时S1发送的投票命令。因为S2已经在T3时同意了S3的投票请求,此时,S2给S1回复N,表示不同意S1称为leader。发生这种情况,是因为S3和S2之间的网络传输正常,而S1和S2之间的网络传输可能正好拥塞 了,导致投票请求传输慢了。
  • 最后,在T5时刻,S1得到的票数是来自它自己的一票Y和来自S2的一票N。而S3除了自己的赞成票Y以外,还收到了来自S2的一票Y。此时,S3不仅获得了半数以上的赞成票,也达到预设的quorum值(2),所以他成为了Leader。接着,S3会开始执行选主操作,而且在选定新主库后,会给其他从库和客户端通知新主库的信息。
  • 如果S3没拿到2票Y,那么这轮投票就不会产生Leader。哨兵集群会等待一段时间(也就是哨兵故障转移超时时间的2倍),在重新选举。这是因为。哨兵集群能够进行成功投票,很大程度上依赖于选举命令的正常网络传播。如果网络压力较大或有时堵塞,就可能导致没有一个哨兵能拿到半数以上的咋赞成票,所以,等到网络拥塞好转后,在进行投票选举,成功的概率会增加。

需要注意的是,如果哨兵集群只有两个实例,此时一个哨兵要想成为leader,必须获得两票,而不是一票。所以,如果有个哨兵挂掉了,那么,此时的集群是无法进行主从库切换的。因此,通常我们至少会配置3个哨兵实例。

小结:

通常,我们在解决一个问题的时候,会引入一个新机制,或者设计一层新功能,就像我们在这两节课学习的内容:为了实现主从切换,我们引入了哨兵;为了避免单个哨兵故障后无法进入主从切换,以及为了减少误判率;哨兵集群又需要有一些机制来支撑他的正常运行。
本节课主要学了支持哨兵集群的这些关键字

  1. 基于pub/sub机制的哨集群组队过程。
  2. 基于INFO命令的从库列表,这可以帮助哨兵和从库建立连接。
  3. 基于哨兵自身的pub/sub功能,这实现了客户端和哨兵之间的事情。
    对于主从切换,当然不是哪个哨兵想执行就可以执行的,否则就乱套了。所以,这就需要哨兵集群在判断主库“客观下线”后,经过仲裁投票,选举出一个Leader出来,由他负责实际的主从切换,即由它来完成新主库的选择以及通知从库与客户端。
    要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值down-after-milliseconds
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐