redis哨兵机制原理
# 哨兵机制
无论是写服务中断,还是从库无法进行数据同步,都是不能接受的。所以,如果主库挂了,我们就需要运行一个新主库,比如说把一个从库切换为主库,把它当成主库。这就涉及到三个问题:
- 主库真的挂了吗?(监控)
- 该选择哪个从库作为主库?(决策)
- 怎么把新主库的相关信息通知给从库和客户端呢?(通知)
# 哨兵机制的基本流程
# 哨兵的监控
# 主观下线和客观下线
哨兵通过给主库,从库发送ping命令,如果没有在规定时间内响应,哨兵则认为主库或从库下线,也叫“主观下线”。
但是仅仅通过一个哨兵是不够的,因为一个哨兵可能会存在误判,就像人做判断时,也经常会有误判的时候,所以得有一个哨兵集群来一起ping 主库或从库,如果半数以上的哨兵都认为其下线,那么其就是“客观下线”。
# 哨兵的决策
主库下线了,需要快速的选举新的主库,避免客户端的命令很长时间没有被执行,那么谁来当主库,谁来决定哪个从库成为主库呢?
哨兵会通过一系列的策略来给从库打分,进而筛选优良的从库:
- 淘汰网络环境不好的从库(配置项
down-after-milliseconds * 10
主从库断连的最大连接超时时间) - 最高的优先级,得分高(slave-priority 配置项)
- 与旧主库同步最高的,得分高(比对主从的offset 在 repl_backlog_buffer (固定复制缓冲区)的位置 )
- id最小,得分高(runId )
# 哨兵的通知
先把这个问题记下:怎么把新主库的相关信息通知给从库和客户端呢?先往下说
因为为了提高主从机制的高可用性,而引入哨兵集群,而这也会带来些问题:
- 其中一个哨兵挂了,会不会影响主库的选举?(不会,集群机制,挂了一个,只要有存活的就是可用状态)
- 选举某个从库为主库之后的操作,由哪个哨兵执行?(后面说)
# 哨兵通知的条件
因为哨兵需要选举其中一个从库为主库,那么得先知道这些信息
在判断主库是否下线时,哨兵是互相知道彼此的存在的,而且可以互通消息 - 哨兵与哨兵通信
哨兵监控从库,切换主库后,需要通知从库;哨兵得先知道有哪些从库,而且可以哨兵可以获取从库的信息 - 哨兵与从库通信
当新的主库被推举后,客户端的命令写的地址需要被修改,需要指向新的主库,哨兵和客户端需要通信 - 哨兵与客户端通信
上面三个通信问题是实现切换主库的必要条件,看看redis作者是如何解决的。
# 哨兵与哨兵通信
根据redis的pub/sub机制,哨兵可以在主库上订阅频道,发送消息,订阅者可以接受到消息,比如哨兵1在主库的频道sentinel:hello
上发送“我想吃饼”,其他哨兵都已经订阅了这个频道,都会收到“我想吃饼”的消息,这样就实现了哨兵可以获取其他哨兵的信息,之后哨兵只会通过命令通信
注意
哨兵初次连接需要通过订阅主库上的频道 获取其他哨兵的信息,之后哨兵之间直接通过命令传播互相通信。
# 哨兵与从库通信
哨兵既然可以与主库通信,那么哨兵可以通过发送info
命令给主库,获取其从库的信息(ip+port),继而对从库进行连接。
# 哨兵与客户端通信
哨兵也可以有自己的pub/sub机制,发布自己的频道,客户端可以通过订阅对应的频道获取信息,包括主库下线判断、新主库选定、从库重新配置。
# 哨兵和主库
哨兵是通过客户端发来的
sentinel monitor <master-name> <ip> <redis-port> <quorum>
命令知道主库的ip和端口的
# 由哪个哨兵执行主从切换?
选举哪个哨兵来进行主从切换,发生在哨兵判断“主观下线”的时候
**投票时机:**任何一个实例只要自身判断主库“主观下线”后,就会给其他实例发送 is-master-down-by-addr 命令,接着,其他实例会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。
**选举条件:**第一,拿到半数以上的赞成票;第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值
达成条件的哨兵会成为哨兵leader 执行对主从切换
# 注意
如果哨兵集群只有 2 个实例,此时,一个哨兵要想成为 Leader,必须获得 2 票,而不是 1 票。所以,如果有个哨兵挂掉了,那么,此时的集群是无法进行主从库切换的。因此,通常我们至少会配置 3 个哨兵实例。
# 分享经验
要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds。我们曾经就踩过一个“坑”。当时,在我们的项目中,因为这个值在不同的哨兵实例上配置不一致,导致哨兵集群一直没有对有故障的主库形成共识,也就没有及时切换主库,最终的结果就是集群服务不稳定。所以,你一定不要忽略这条看似简单的经验。