Redis的哨兵机制可以实现主从库的自动切换,通过部署多个哨兵实例,就形成了一个哨兵集群。哨兵集群中的多个实例共同判断,可以降低对主库下线的误判。一旦实例组成了哨兵集群,即使有哨兵实例出现故障挂掉了,其他哨兵还能继续完成主从库切换工作。
在配置哨兵信息时,只需以下配置,设置主库IP和端口,并没有配置其他哨兵的连接信息。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
这些哨兵实例都不知道彼此的地址,又怎么组建集群呢?
哨兵实例之间可以相互发现,要归功于Redis提供pub/sub机制,也就是发布/订阅机制。
哨兵只要和主库建立起了连接,就可以在主库上发布消息了,比如发布它自己的连接信息(IP和端口)。同时也可以从主库上订阅消息,获取其他哨兵发布的连接信息。
除了哨兵实例,我们自己编写的应用程序也可以通过Redis进行消息的发布和订阅。只有订阅了同一个频道的应用,才能通过发布的消息进行信息交换。
在主从集群中,主库上有一个名为“_ _sentinel_ _:hello”的频道,不同哨兵就是通过它来相互发现,相互通信的。
哨兵除了彼此之间建立起连接形成集群外,还需要和从库建立连接。那么哨兵如何知道从库的IP和端口的呢?
这是由哨兵向主库发送info命令来完成的,主库接收到这个命令后,就会把从库列表返回给哨兵,哨兵就可以根据从库列表中的连接信息和每个从库建立连接,并在这个连接上持续对从库就行监控。
但是,哨兵不能只和主、从库连接,因为主从库切换后,客户端也需要知道新主库的连接信息,所以,哨兵还需要完成把新主库的信息告诉客户端。
依然可以使用pub/sub机制,来实现哨兵和客户端之间的信息同步。从本质上来说,哨兵就是运行在特定模式下的Redis实例,只不过它不服务请求操作,只完成监控、选主、通知的任务。所以,每个哨兵实例也提供pub/sub机制,客户端可以从哨兵订阅消息。哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键使事件。
客户端读取哨兵的配置文件后,可以获得哨兵的地址和端口,和哨兵建立网络连接。然后客户端执行订阅命令。
SUBSCRIBE +odown
SUBSCRIBE *
有了pub/sub机制,哨兵和哨兵之间、哨兵和从库之间、哨兵和客户端之间就能建立起连接了。
主库故障后,哨兵集群有多个实例,由哪个哨兵执行主从切换呢?
一个哨兵获得仲裁所需的赞成票后,就可以标记主库为“客观下线”。这个所需赞成票数是通过哨兵配置文件中的quorum配置项设定的。此时,这个哨兵就可以再给其他哨兵发送命令,表明希望由自己来执行主从切换,并让其他少比你高进行投票。这个投票过程称为“Leader选举”。
任何一个想称为Leader的哨兵,要满足两个条件:
- 拿到半数以上的赞成票;
- 拿到的票数同时还需要大于等于哨兵配置文件中的quorum值。
如果哨兵实例只有2个,一个哨兵想成为Leader,必要获得2票,如果有个哨兵挂掉了,集群是无法进行主从切换的,因此,通常情况下至少配置3个哨兵实例。
哨兵集群的关键机制:
- 基于pub/sub机制的哨兵集群组成过程;
- 基于INFO命令的从库列表,这可以帮助哨兵和主从库建立连接;
- 基于哨兵自身的pub/sub功能,实现了客户端和哨兵之间的事件通知。
要保证所以哨兵实例的配置是一致的,尤其是主观下线的判断值down-after-milliseconds。