# 哨兵集群：哨兵挂了，主从库还能切换吗

![](https://z3.ax1x.com/2021/07/31/Wvp8JK.png)

# 核心知识提炼

## 1、哨兵集群

多个哨兵实例组成了哨兵集群，这样如果其中某个哨兵挂了的话，其它哨兵还是可以继续协作。

配置哨兵的时候，会用到下面的命令设置主库的IP和端口。

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

## 2、基于 pub/sub 机制的哨兵集群组成

哨兵实例都不知道彼此的地址，又是如何组成集群的呢？这要归功于 pub/sub 机制。

哨兵只要和主库建立了连接，就可以在主库上发送消息了，比如发布它自己的连接信息（IP和端口），同时也可以从主库上订阅消息，获得其它哨兵的信息。

**当多个哨兵实例都在主库上做了发布和订阅操作之后，彼此的 IP 地址和端口也就知道了。**

这里需要注意的是，只有订阅了同一个频道的应用，才能通过发布的消息进行信息交换。

## 3、哨兵是如何知道从库的 IP 地址和端口呢？

通过哨兵由主库发送 INFO 命令来完成，主库收到命令之后，就会把从库列表返回给哨兵，后面，哨兵就可以根据从库列表中的信息，和每个从库建立连接，并在这个连接上持续地对从库进行监控。

![](https://cdn.jsdelivr.net/gh/rongweihe/ImageHost01/redis0802.png)

## 4、哨兵和客户端之间信息同步

前面第三步之后，我们发现，哨兵不能之和主、从库连接。因为，主从库切换之后，客户端也需要知道新主库的连接信息，才能向新主库发送请求操作。所以，哨兵还需要把新主库的信息也告诉客户端。

那么这一步，其实也是通过 pub/sub 机制来实现的。

本质上来说，哨兵就是一个运行在特定模式下的 Redis 实例，只不过它并不服务请求操作，只是完成监控、选主和通知的任务。

所以，每个哨兵实例也提供了 pub/sub 实例，客户端可以从哨兵订阅消息。

![](https://cdn.jsdelivr.net/gh/rongweihe/ImageHost01/redis0803.png)

比如，订阅“所有实例进入客观下线状态的事件”

```c
subscribe +odown
```

订阅所有的事件：

```c
subscribe *
```

当哨兵选择了新主库，客户端就会看到下面的 switch-master 事件。这个事件表示主库已经切换了，新主库的 IP 地址和端口信息已经有了。

这个时候，客户端就可以用新的主库地址和端口进行通信：

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

有了 pub/sub机制，哨兵和哨兵之间、哨兵和从库之间、哨兵和客户端之间就都能建立起连接了。

## 5、由哪个哨兵进行主从切换？

也需要一个“投票仲裁”的过程。

任何一个想成为 Leader 的哨兵，需要满足两个条件：

- 第一，拿到半数以上的赞成票。
- 拿到的票数同时还要大于等于哨兵配置中的 quorum 值。

![](https://cdn.jsdelivr.net/gh/rongweihe/ImageHost01/redis08055.png)

## 6、如何避免哨兵不能投票给自己？

- 不同哨兵的网络连接-系统压力不一样，接收到下线协商信息时间也可能不同，所以同时做出主库下线判定的概率比较小，一般都有个先后关系。
- 其次，哨兵对主库进行的在线状态判定，是属于一种时间事件，会有一个定时器完成，一般来说100m执行一次这些时间，每个哨兵的定时器执行周期会加上一个小小的随机数来偏移。
- 即使出现了都投给自己一票的情况，导致无法选出 Leader，哨兵会停一段时间（一般是故障转移超时时间failover_timeout 的 2 倍），然后再可以进行下一轮投票。
- 哨兵如果没有给自己投票，就会把票投给第一个给它发送投票请求的哨兵。后续再有投票请求来，哨兵就拒接投票了。

# 总结

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

支持哨兵集群的这些关键机制，包括：

- 基于 pub/sub 机制的哨兵集群组成过程； 
- 基于 INFO 命令的从库列表，这可以帮助哨兵和从库建立连接； 
- 基于哨兵自身的 pub/sub 功能，这实现了客户端和哨兵之间的事件通知。

对于主从切换，当然不是哪个哨兵想执行就可以执行的，否则就乱套了。所以，这就需要 哨兵集群在判断了主库“客观下线”后，经过投票仲裁，选举一个 Leader 出来，由它负责 实际的主从切换，即由它来完成新主库的选择以及通知从库与客户端。

最后，就是要注意：**要保证所有哨兵实例的配置是一致的，尤其是主观下线 的判断值 down-after-milliseconds。**