在配置哨兵的信息时,我们只需要用到下面的这个配置项,设置主库的 IP 和端口,并没有配置其他哨兵的连接信息。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
这些哨兵实例既然都不知道彼此的地址,又是怎么组成集群的呢?要弄明白这个问题,我们就需要学习一下哨兵集群的组成和运行机制了。
基于 pub/sub 机制的哨兵集群组成
哨兵实例之间通过主库可以相互发现相互连接,要归功于 Redis 提供的 pub/sub 机制,也就是发布 / 订阅机制。只有订阅了同一个频道的应用,才能通过发布的消息进行信息交换。在主从集群中,主库上有一个名为“__sentinel__:hello”的频道,不同哨兵就是通过它来相互发现,实现互相通信的。
哨兵是如何知道从库的 IP 地址和端口的呢?
由哨兵向主库发送 INFO 命令来完成,主库接受到这个命令后,就会把从库列表返回给哨兵。
哨兵不能只和主、从库连接。因为,主从库切换后,客户端也需要知道新主库的连接信息,才能向新主库发送请求操作。所以,哨兵还需要完成把新主库的信息告诉客户端这个任务。
基于 pub/sub 机制的客户端事件通知
如何在客户端通过监控了解哨兵进行主从切换的过程呢?比如说,主从切换进行到哪一步了?仍然可以依赖 pub/sub 机制,来帮助我们完成哨兵和客户端间的信息同步。从本质上说,哨兵就是一个运行在特定模式下的 Redis 实例,只不过它并不服务请求操作,只是完成监控、选主和通知的任务。几个关键事件的频道:
举个例子,订阅所有实例进入客观下线状态的事件:
SUBSCRIBE +odown
用模式订阅所有的事件:
PSUBSCRIBE *
模式订阅psubscribe最大的特点是,它除了可以通过Channel订阅消息以外,还可以配合配置命令来进行Keys信息变化的事件通知。
当哨兵把新主库选择出来后,客户端就会看到下面的 switch-master 事件,这个时候,客户端就可以用这里面的新主库地址和端口进行通信。
switch-master <master name> <oldip> <oldport> <newip> <newport>
怎么确定由哪个哨兵来进行实际的主从切换呢?
确定由哪个哨兵执行主从切换的过程,和主库“客观下线”的判断过程类似,也是一个“投票仲裁”的过程。任何一个实例只要自身判断主库“主观下线”后,就会给其他实例发送 is-master-down-by-addr 命令。一个哨兵获得了仲裁所需的赞成票数后,就可以标记主库为“客观下线”。这个所需的赞成票数是通过哨兵配置文件中的 quorum 配置项设定的。
此时,这个哨兵就可以再给其他哨兵发送命令,表明希望由自己来执行主从切换,并让所有其他哨兵进行投票。这个投票过程称为“Leader 选举”。因为最终执行主从切换的哨兵称为 Leader,投票过程就是确定 Leader。
如果 S3 没有拿到 2 票 Y,那么这轮投票就不会产生 Leader。哨兵集群会等待一段时间(也就是哨兵故障转移超时时间failover_timeout的 2 倍),再重新选举。这是因为,哨兵集群能够进行成功投票,很大程度上依赖于选举命令的正常网络传播。如果网络压力较大或有短时堵塞,就可能导致没有一个哨兵能拿到半数以上的赞成票。所以,等到网络拥塞好转之后,再进行投票选举,成功的概率就会增加。通常我们至少会配置 3 个哨兵实例。要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds。
哨兵实例是不是越多越好?
并不是,哨兵在判定“主观下线”和选举“哨兵领导者”时,都需要和其他节点进行通信,交换信息,哨兵实例越多,通信的次数也就越多,而且部署多个哨兵时,会分布在不同机器上,节点越多带来的机器故障风险也会越大,这些问题都会影响到哨兵的通信和选举,出问题时也就意味着选举时间会变长,切换主从的时间变久。
--内容整理自极客时间《Redis 核心技术与实战》