(九)Redis 哨兵机制与集群

主从复制中,如果从库发生故障了,客户端可以继续向主库或其他从库发送请求,但是如果主库发生故障了肿么办呢?读请求,那还可以由从库继续提供服务,写请求就么得办法了。此时,哨兵机制就登场了,解决3个问题:
(1)主库真的挂了吗?
(2)该选择哪个从库作为主库?
(3)怎么把新主库的相关信息通知给从库和客户端呢?

哨兵就是一个运行在特殊模式下的 Redis 进程,与主从库实例同时运行,主要负责的就是3个任务:监控、选主、通知:
(1)监控:是指哨兵进程在运行时,周期性地给所有的主从库发送 PING 命令,检测它们是否仍然在线运行,没有在规定时间内响应哨兵的 PING 命令,哨兵就会把它标记为"下线状态",如果是主库下线,自动开始切换主库的流程。
(2)选主:是指主库挂了以后,哨兵就需要从很多个从库里,按照一定的规则选择一个从库实例,把它作为新的主库。这一步完成后,集群里就有了新主库。
(3)通知:是指哨兵会把新主库的连接信息发给其他从库,让它们执行 replicaof 命令,和新主库建立连接,并进行数据复制。同时,把新主库的连接信息通知给客户端,让它们把请求操作发到新主库上。 在这三个任务中,通知任务相对来说比较简单,哨兵只需要把新主库信息发给从库和客户端,让它们和新主库建立连接就行,并不涉及决策的逻辑。而监控和选主这两个任务中,哨兵需要做出两个决策:
(1)在监控任务中,哨兵需要判断主库是否处于下线状态
(2)在选主任务中,哨兵也要决定选择哪个从库实例作为主库

监控
主库的下线状态有"主观下线"和"客观下线"两种,当 PING 命令的响应超时了,那么,哨兵就会先把它标记为"主观下线"。如果是从库,影响不大,如果是主库,就要开始选主。一旦启动了主从切换,后续的选主和通知操作都会带来额外的计算和通信开销,为了避免这些不必要的开销,我们要特别注意误判的情况。误判就是主库实际并没有下线,但是哨兵误以为它下线了,一般会发生在集群网络压力较大、网络拥塞,或者是主库本身压力较大的情况下。
通常会采用多哨兵组成的集群模式进行部署,降低误判的概率,这也被称为哨兵集群。大多数的哨兵都判断主库已经"主观下线"了,主库才会被标记为"客观下线",判断原则就是:少数服从多数。
简单来说,"客观下线"的标准就是,当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为"主观下线",才能最终判定主库为"客观下线"。这样一来,就可以减少误判的概率,也能避免误判带来的无谓的主从库切换。(当然,有多少个实例做出"主观下线"的判断才可以,可以由 Redis 管理员自行设定)**

选主
在选主时,要先保证所选的从库仍然在线运行,还要判断它之前的网络连接状态,如果从库总是和主库连接的网络状况并不是太好,就要这个从库筛掉了。具体判断规则是配置项 down-after-milliseconds * 10,down-after-milliseconds 是我们认定主从库断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从库的网络状况不好,不适合作为新主库。

剩余的从库按3个规则依次打分,只要在某一轮中,有从库得分最高,那么它就是主库了,选主过程到此结束。如果没有出现得分最高的从库,那么就继续进行下一轮。

(1)优先级最高的从库得分高
slave-priority 优先级配置项,比如某个从库内存最大设置了高优先级,将会优先成为新主库,否则进入下一轮打分。

(2)和旧主库同步程度最接近的从库得分高
如果有从库的 slave_repl_offset 最接近旧主库 master_repl_offset,那么它的得分就最高,否则进入下一轮打分。

(3)ID 号小的从库得分高
每个实例都会有一个 ID,在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。

哨兵选择新主库的过程称可以总结为"筛选 + 打分",按照在线状态、网络状态,筛选过滤掉一部分不符合要求的从库,然后,依次按照优先级、复制进度、ID 号大小再对剩余的从库进行打分,只要有得分最高的从库出现,就把它选为新主库。