redis(四) 哨兵

199 阅读5分钟

哨兵

在集群中需要一个哨兵这样的角色,来完成监控实例的上下线,还有选举出新的主库,监控、选主(选择主库)和通知。这里的哨兵一般情况下不是什么特殊的新的东东,就是一个普通的redis实例,只是该实例不用来存储数据,然后专门用来承担哨兵的功能。
有一个想法,既然哨兵也是一个redis,那么是否在主从集群多数宕机的情况下,自动快速加入主从集群,充当一个存储实例。

哨兵看到了什么

哨兵通过,隔一段时间发送ping 命令 ,来检测该实例是否下线。如果没有按时回应,则认为下线了。一般情况下哨兵自身也是一个集群,拥有多个实例。和现实中一样,人数多的团队中需要进行大家的意见收集,才可以良性管理。一个哨兵的判断可能受到网络,主库性能波动等影响导致误判。此时延伸出2个概念

主观下线

主观下线由一个哨兵判断,哨兵 去每隔 1秒钟就像架构中所有的机器去ping一下,如果一台机器距离最后一次ping命令的时间超过 down-after-miliseconds配置的值就会被该哨兵标记为主观下线(SDOWN)

客观下线

redis 配置 quorum 数量,当有超过这个数量的哨兵认为该节点下线时,则认为该节点客观下线,也就是说真正的被标记上了下线的标记。此时也存在一个问题,当哨兵挂了很多,剩下的哨兵不足以完成quorum这个数量时,哨兵就无法监控到已经下线的节点。但是考虑到,哨兵本身不承担存储任务,故性能压力等较小,发生大面积挂机的几率不高

哨兵订阅

redis 提供了pub/sub机制,当一个哨兵与主库建立起连接后,会发布这个哨兵的消息给其他哨兵。同时也会订阅其他哨兵的消息,获得其他哨兵的信息。故在建立哨兵时,只需要配置主库的地址和端口信息就可以。和dubbo的注册中心有着异曲同工之妙。

只有订阅了同一个频道的应用,才能通过发布的消息进行信息交换,在主从集群中,主库上有一个名为“sentinel:hello”的频道,不同哨兵就是通过它来相互发现,实现互相通信的

主库知道以后,哨兵从主库中获取从库的连接列表,也感知到了所有的从库。

客户端可以获取到哨兵集群在监控,选主,通知 切换等各种事件,从而维护一个可用的redis列表和主库信息

哪一个哨兵来“开枪”

哨兵,在检测到主库下线后,需要快速选举一个从库来做新的主库,需要发送给每一个从库这个信息。把剩下的从库和新主库建立起关系来,并通知给客户端。此过程需要发生2个重大的选举。

哨兵选举

哨兵A|B|C|D|E

1、A最先开始发现了主库为主观下线,此时向其他的哨兵发起询问,判断是否主库真的下线了
2、此时,其他的哨兵会发起请求,并把自己的答案会应给哨兵A
3、哨兵A收到消息后,为客观下线,就希望自己可以来完成主从的切换,此时会再次想哨兵们询问自己是否可以执行
4、哨兵A能否执行,需要完成2个条件,一个是超过半数的哨兵同意,第二个是拿到的票数同时需要大于等于哨兵配置文件中的quorum
5、哨兵A向所有的从库发送信息重新选举主库

实际上,这里的选举情况多种多样,但是保持一个原则,一个哨兵在一轮投票中只能投出一票同意票,包括自己,果然当A发现时,B也发现了,那么B也会发起询问自己是否可以,同时A的请求到B时,得到的答复是不赞成,因为自己也要当。反之B的请求到达A时,也是这样的答复。

从库选举

从库中需要选举出一个新的主库,首先要过滤不健康的节点,不然它当上了主库,马上又挂了,又要费事选举了。 主观下线的,大于5秒未回应的,与master节点失联的 这些就是不够健康的节点

再根据3个优先级进行选举

  • 配置优先级 slave-priority 配置的信息,默认100 ,值最低成为主
  • slave_repl_offset 与旧的主库最接近的为主,这里是主从同步之间拥有一个环形内存,只是主库已经挂了,无法获取master_repl_offset,此时只需要比较slave_repl_offset的大小即可,最大的最接近。
  • runid 最小的为主

哨兵集群

可以总结在判断下线和选举主库时,哨兵之间要彼此进行多次通信交换信息,所以哨兵越多并不是越安全越靠谱,反而多个哨兵的情况下,需要更多的选举时间,主从切换的时间也会边久。此时,隔壁的ZK又做了一个操作,在主从的节点上,增加了一个observer的节点,只同步数据,但是不存与任何的投票,有点像工具人。

调大 down-after-milliseconds 可以减少误判,但是错误发生时,检测的灵敏度也会下降