上一篇介绍了`Redis`中的主从复制。我们知道`Redis`主从中一般只有主节点对外提供写操作,如果主节点发生故障,为了保证`Redis`的可用性,这时就要在可用的`slave`节点中,挑选一个作为主节点。这种切换操作如果是人为的操作,那么存在一定的延时性,且耗费较大的人力。为了解决这个问题,`Redis`提供了一种模式--那就是**哨兵模式**。
Redis哨兵模式是一个分布式系统,监控主从架构中的节点。通过自动故障转移,保证集群的**高可用。**哨兵也是一台Redis服务器,只是不提供任何服务,推荐配置为单数(避免投票时出现相同票)。
1、主要结构
1.1、单哨兵模式
1.2、多哨兵模式
2、主要功能
2.1、监控
Sentinel会不间断的监控主节点和从节点是否正常。
2.2、通知
当Sentinel检测到某个节点出现异常时,会通知其他哨兵。
2.3、自动故障转移
当主服务器出现故障时,Sentinel会进行一次自动故障转移,它会从失效的主服务器的从服务器中选择出一个可用的从服务器作为新的主服务器,并通知失效的主服务器的从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新的主服务器地址,使得集群可以使用主服务器替换失效的服务器。
3、Sentinel工作原理分析
3.1、哨兵文件详解
配置1:sentinel monitor master-name ip port quorum
这个配置文件表示的是,哨兵定期监控名字叫做master-name
IP为ip
,端口为port
的主节点。quorum
表示的哨兵判断主节点是否发生故障的票数。也就是说如果我将quorum
设置为2,那么就代表至少要有两个哨兵认为主节点故障了,才算这个主节点是客观下线的。一般设置为sentinel
节点数的一半加一。
配置2:sentinel down-after-millseconds master-name times
每个哨兵节点会定期发送ping
命令来判断Redis
节点和其余的哨兵节点是否可达的,如果超过了配置的times
时间没有收到pong
回复,就主观判断节点是不可达的。times
单位为毫秒。
配置3:sentinel parallel-syncs master-name nums
当哨兵节点认为主节点故障时,哨兵投票选出的leader
会进行故障转移,选出新的主节点,原来的从节点们会向新的主节点复制。这个配置就是来控制在故障转移之后,每次可以向新的主节点发起复制的节点个数,最多为nums
个,因为如果不加控制会对主节点的网络和磁盘IO资源带来较大的压力。
配置4:sentinel failover-timeout master-name times
这个代表哨兵进行故障转移时,如果超过了配置的times
时间就表示故障转移失败。
配置5:sentinel auth-pass master-name password
如果主节点设置了密码,则需要这个配置,否则哨兵无法对主节点进行监控。
3.2、为什么用到哨兵
哨兵主要是为了解决在主从复制架构中出现宕机的情况。主要分为两种情况:
3.2.1、从Redis宕机
这个相对来说简单些,在Redis
中从库重新启动后会自动加入到主从架构中,自动完成数据同步。在Redis 2.8
之后,主从断线后,数据恢复采用增量复制。
3.2.2、主Redis宕机
这个相对来说复杂点,需要以下两步才能完成
- 在从数据库中执行
slaveof no noe
命令,断开主从关系并且提升为主库继续服务。 - 将主库重新启动后,执行
slaveof 新的master-ip port
命令将其设置从库,这时数据就能更新回来,以从库的方式继续提供服务。
由于这个手动操作的过程其实是比较麻烦的并且容易出错,所以Redis
提供了**哨兵模式(Sentinel)**来解决这个问题。
3.2.3、主观下线
主观下线就是单个Sentinel认为某个服务下线。Sentinel会以每秒一次的频率向所有与其建立了命令连接的实例(master,从服务,其他Sentinel)发送ping命令,通过判断ping命令回复是有效回复还是无效回复判断实例是否在线(对该Sentinel来说是主观下线)。
Sentinel配置文件中的down-after-millseconds
设置了判断主观下线的时间长度,如果实例在down-afetr-millseconds
毫秒内,没有收到有效回复(pong),那么Sentinel会认为(主观)该实例已经下线,修改状态为SRI_S_DOWN
。如果多个Sentinel监视一个服务,有可能存在多个Sentinel的down-after-mullseconds
配置不同。
3.2.4、客观下线
当主观下线的节点是主节点时,此时该哨兵节点会通过指令Sentinel is-master-down-by-addr
寻求其他Sentinel节点对主节点的判断,如果其他Sentinel节点也认为主节点客观下线,且认为主观下线的票数超过了quorum(选举个数)
,此时哨兵节点则认为该主节点确实有问题,认为其事客观下线。
4、哨兵的三个定时任务监控
4.1、任务1
每个哨兵每10秒会向主节点和从节点发送info命令获取最新的拓扑结构图,哨兵配置时,只需要配置对主节点的监控即可,通过向主节点发送info命令,获取从节点的信息,并当有新的从节点假如时,可以马上感知到。
4.2、任务2
每个哨兵节点每隔2秒会向Redis
数据节点的指定频道发送该哨兵节点对于主节点的判断,以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其他哨兵节点的信息及对主节点的判断,其实就是通过消息的publish
和subscribe
来完成的。
4.3、任务3
每隔1秒,每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping
命令做一次心跳检测,这个也是哨兵用来判断节点是否正常的重要依据。
5、Sentinel的leader选举流程
如果主节点被认为是客观下线之后就会选取一个哨兵节点来完成后面的故障转移工作,选举出一个leader的过程如下:
- 每个在线的哨兵节点都可以成为leader,当它确认(比如上图的哨兵3)主节点下线时,会向其他哨兵发送
is-master-down-by-addr
命令,征求其他哨兵的判断,并且将自己设置为leader,由leader来处理故障转移。 - 当其他哨兵收到此消息时,可以同意或者拒绝它成为领导者。
- 如果哨兵3发现自己在选举中的票数大于
num(Sentinel)/2+1时,将成为领导者,如果没有超过,则继续选举。
6、自动故障转移机制
在从节点中选择新的主节点。
Sentinel状态数据结构中保存了主服务的所有从服务信息。Sentinel中的leader按照如下规则在从服务中选择一个作为新的主服务。
- 过滤掉主观下线的节点
- 选择
slave-priority
最高的节点,如果有则返回,没有就继续选择。 - 选择复制偏移量最大的节点,因为复制偏移量越大,说明数据越完整,如果有则返回,没有继续选择。
- 选择run_id最小的节点
通过slaveof no one
,让选出来的从节点成为主节点;并通过slaveof
命令让其他从节点复制新的主节点。将下线的主节点设置成新主节点的从节点,当其回复正常时,复制新的主节点,变成新主节点的从节点。
7、Sentinel工作原理总结
- 每个Sentinel以每秒一次的频率向他所知master、slave以及其他Sentinel发送一次
ping
命令。 - 如果一个实例距离最后一次回复
ping
命令的时间超过down-after-millseconds
指定的值,则这个实例会被Sentinel标记为主观下线。 - 如果一个master被标记为主观下线,则正在监控这个master的其他Sentinel要以每秒一次的频率确认master是否进入主观下线。
- 如果有足够数量的Sentinel(大于等于
quorum
指定的值)认为master确实处于主观下线状态,那么master会被标记为客观下线。 - 在一般情况下,每个Sentinel要以每10秒一次的频率向已知的master、slave发送
info
命令。 - 当master被标记为客观下线后,Sentinel向下线的master的所有slave发送info命令的频率会从10秒一次改为每秒一次。