哨兵挂了,主从库还能切换吗?

内容参考蒋德钧老师讲义

上一节,了解了哨兵机制,它可以实现主从库的自动切换。通过部署多个实例,就形成了哨兵集群。哨兵集群中的多个实例共同判断,可以降低对主库下线的误判率。

但是,还有一个要考虑的问题:如果有哨兵实例运行时发生了故障,主从库还能正常切换吗?

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

在配置哨兵信息时,只需要用到下面的这个配置项,设置主库IP端口,并没有配置其他哨兵的连接信息

sentinel monotor <master-name> <ip> <redis-port> <quorum>
quorum 表示投票需要的最少法定人数,即假设需要3个哨兵认为主库主观下线才能判断主库为客观下线,那么quorum=3

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

基于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建立网络连接。通过这个方式,哨兵2和哨兵3也可以建立网络连接,这样一来,哨兵集群就形成了。他们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事进行协商。

哨兵除了能彼此之间建立起连接形成集群外,还需要和从库建立连接。这是因为,在哨兵的监控任务中,他需要对主从库都进行心跳判断,而且在主从库切换完成后,它还需要通知从库,让他们和新主库进行同步。

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

只是由哨兵想主库发送INFO命令来完成的。就像下图一样,哨兵2给主库发送INFO命令,主库接受到这个命令之后,就会把从库列表返回给哨兵。接着,哨兵就可以根据从库列表中的连接信息,和每个从库建立连接,并在这个连接上持续的对从库进行监控。哨兵1和哨兵3可以通过相同的方法和从库建立连接。

你看,通过pub/sub机制,哨兵之间可以组成集群,同时,哨兵又通过INFO命令,获得了从库的连接信息,也能和从库建立连接,并进行监控。

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

而且,在实际使用哨兵时,我们有时会遇到这样的问题:如何在客户端通过监控了解哨兵进行主从切换呢?比如说,主从切换进行到哪一步了?这其实就是要求客户端能够获取到哨兵集群在监控、选主、切换过程中发生的各种事情。

此时,我们仍然可以使用pub/sub机制,来帮助我们完成哨兵和客户端之间的通信。

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

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

下面列出几个关键的频道

知道了这些频道之后,你就可以让客户端从哨兵这里订阅消息了。具体操作步骤是,客户端读取哨兵的配置文件后,可以获得哨兵的地址和端口,和哨兵建立网络连接。然后,我们可以在客户端执行订阅命令,来获取不同的事件消息。

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

subscribe +odown

当然,你也可以执行如下命令,订阅所有的事件

psubscribe *

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

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

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

由哪一个哨兵执行主从切换

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

哨兵集群要判定主库“客观下线”,需要由一定数量的实例都认为主库已经“主观下线”了

任何一个实例只要自身判断主库“主观下线”后,就会给其他实例发送 is-master-down-by-addr命令。接着实例会根据自身和主库的连接情况,做出Y或N的响应,Y相当于赞成票,N相当于反对票。

一个哨兵获得了仲裁所需的赞成票数后,就可以标记主库为“客观下线”。这个所需的赞成票数是通过哨兵配置文件的 quorum 配置项设定的。例如,现在有5个哨兵,quorum配置的是3,那么,一个哨兵需要3张赞成票,就可以标记主库为“客观下线”了。这三张赞成票包括自己的一张和另外两个哨兵的赞成票。

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

在投票过程中,任何一个想成为Leader的哨兵,要满足两个条件:第一,拿到半数以上的赞成票;第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum值。以3个哨兵为例,假设此时 quorun设置为2,任何一个想成为leader的哨兵只需要拿到2张赞成票,就可以了。

如果没有达到要求,那么这一轮就不会产生leader。哨兵集群会等待一段时间(也就是哨兵故障转移超时时间的2倍),再重新选举。这是因为哨兵集群能够进行成功投票,很大程度上依赖于选举命令的正常网络传播。如果网络压力较大或有短时拥堵,就可能导致没有一个哨兵能拿到半数以上的赞成票。所以,等到网络拥塞好了之后,在进行投票,成功的机率就会增加。

posted @ 2021-05-27 10:31  刘指导  阅读(179)  评论(0编辑  收藏  举报