《redis的pub/sub机制》
【redis pub/sub机制导读】上一节介绍了redis的哨兵机制,其中提到了哨兵集群,但是有很多细节没有深入,假设哨兵集群中有哨兵挂了,哨兵还能继续进行选主、通知、主从切换吗?在协商主库下线的时候,哨兵之间如何进行协商的?因为不同的哨兵位于不同的服务器上。
基于这些场景,redis推出了PUB/SUB(发布/订阅)的机制,何为发布/订阅机制?可以这么理解,redis服务A可以作为一个"广播站",redis服务B可以往redis服务A上发布消息,如果redis服务C想知道redis服务B的消息,那redis服务C可以往redis服务A上订阅消息。这就是发布/订阅的机制。
哨兵只要和主库建立起了连接,就可以在主库上发布消息了,比如:发布自己的IP和监听端口,同时它也可以从主库上订阅其它哨兵的IP和端口信息,哨兵集群中多个哨兵都往主库上发布、订阅消息,那么整个哨兵集群就能获取到彼此的IP和端口了,进而整个哨兵集群之间的交流和通信就不存在障碍了。
我们自己编写的业务程序也可以往redis上发布消息,因为消息的种类有很多,那么redis采用了频道的形式对消息做了区分,只有归属于同个频道的应用,才能通过发布消息进行消息的互换。
在主从集群中,主库上有一个名为“sentinel:hello”的频道,不同哨兵就是通过它来相互发现彼此,实现互相通信的。哨兵之间如何互相发现的,可以参考下图:
好,哨兵可以通过频道、PUB/SUB策略实现相互之间发现和建立联系,那哨兵如何知道从库的IP和端口的,因为哨兵也要PING从库,并将最新主库的信息通知给从库。此时就要用上INFO指令了,哨兵会向主库发出INFO指令,主库收到INFO指令,会把从库的列表信息返回给哨兵。
哨兵和从库建立好连接,假设此时发生了一次主从切换,选出来了最新的主库,那业务方如何知道当前最新的主库信息(IP和端口),这个时候就要用到了订阅机制。
基于 pub/sub机制的客户端事件通知
哨兵其实也是一个特殊模式下的redis进程,只是它不对客户端提供数据增、删、改、查的服务,但它却能为客户端提供消息订阅的服务,比如:主从切换、 主库下线等通知,客户端都能通过订阅的方式获取到这类消息。哨兵提供很多频道,让客户端去订阅这类消息。
比如:客户端想订阅新主库切换事件,可以执行如下的命令:
SUBSCRIBE +switch-master
客户端如果成功订阅到新主机切换事件,那客户端将得到如下的消息报文:
switch-master <master name> <oldip> <oldport> <newip> <newport>
基于此报文,客户端可以用新的IP地址、端口和新的主库通信了。
主从切换具体由哪个哨兵进行负责?
主库“客观下线”是哨兵集群中多个哨兵共同协商的结果,那执行主从切换具体交给哨兵集群中哪个哨兵来负责呢?哨兵集群其实也是有选举的过程的,选出一个哨兵Leader,由Leader执行主从切换。那选举过程是怎样的?
比如:哨兵2通过PING指令判断主库为"主观下线"了,此时它会给其它的哨兵发送is-master-down-by-addr的命令,其它哨兵根据自己和主库的连接情况给出回应,赞同哨兵A的结论,给哨兵A回复Y,不赞成则给哨兵A回复N。
一个哨兵获取到关于"主库主观下线"的赞同意见数(包括自己的意见)超过了quorum中配置的值,那么当前哨兵就会判断主库为“客观下线”。
此时该哨兵将向其它哨兵发送命令(不是is-master-down-by-addr命令),表示自己想成为"主从切换"的Leader,如果当前哨兵收到了其它哨兵的赞成票外加自己的赞成票总数大于等于quorum配置的值,而且赞成票数超过哨兵总数的一半,那么当前哨兵将成为"主从切换"的Leader。
注意:
在举哨兵Leader的过程中,每个哨兵只有投一次"赞成"票的机会。比如哨兵2给自己投了一篇"赞成",此时它收到哨兵1、哨兵3投票的请求,那哨兵2只能给哨兵1、哨兵3回复N。