为了解决主从模式的无法自动容错及恢复的问题,Redis在主从复制的基础上加入了哨兵节点,也就是我们熟悉的哨兵模式。但现在基本不会用到哨兵模式,也就是这种模式只存在于面试中。
一、什么是哨兵模式
ps:主从服务器之间的数据同步在上一篇(主从复制)已经详细介绍过了,本节将不再赘述。
Redis的哨兵模式(Sentinel)是一种高可用的部署方式,由一个或多个Sentinel实例组成的Sentinel系统可以监控和管理多个Redis实例。在哨兵模式下,有一个或多个哨兵进程监控Redis主服务器和备份服务器的状态,并在主服务器下线时自动切换到备份服务器,继续处理命令请求。
如果这时Master进入下线状态,那么slave1和slave2对Master服务器的复制操作会被中止,并且Sentinels系统会觉察到Master已下线,当Master的下线时长超过用户设定的下线时长时,Sentinels系统就会对Master执行故障转移操作:
- Sentinels系统会挑选Master属下的其中一个slave服务器,并把它升级为主服务器。
- 随后,Sentinels系统会向Master属下的所有从服务器发送新的复制指令,让他们称为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕。
- 如果Master重新上线时,它将变为新主服务器的从服务器。
这里就先简单介绍下大致流程,至于如何进行故障检测、如何选举新的主服务器 、如何执行故障操作转移等细节问题,下面会一一介绍。
二、故障检测
2.1 检测主观下线
在默认情况下,Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器和其它Sentinel)发送PING命令,并通过实例返回的PING命令来判断实例是否在线。
ps:实例返回+PONG,-LOADING,-MASTERDOWN三种之一为有效回复,除此之外都是无效回复。
如果一个实例在Sentinel配置文件选项down-after-milliseconds毫秒内,连续向Sentinel返回无效回复,那么Sentinel会修改这个实例所对应的实例结构,在结构flags属性下打开SRI_S_DOWN标识,以此来标记该实例已经进入主观下线状态。
ps:down-after-milliseconds选项配置,不仅会被Sentinel用来判断主服务器的主观下线状态,还会被用于判断主服务器属下的所有从服务器,以及所有同样监视这个主服务器的其他Sentinel的主观下线状态。
2.2 检测客观下线
当Sentinel将一个主服务器判为主观下线后,为了确认这个主服务器是否真下线了,它会同样监视这一服务器的其它Sentinel进行询问,看它们是否也认为主服务器已经进入下线状态(可以是主观或客观下线)。
当认为主服务器已经进入下线状态的Sentinel数量,超过Sentinel配置中设置的quorum参数的值,那么该Sentinle就会认为主服务器已经进入客观下线状态。比如,如果Sentinle启动时载入了以下配置
sentinel monitor master 127.0.0.1 6379 5
那么包括当前Sentinel在内,总过有5个认为主服务器已经下线,当前Sentinel才会将主服务器判断为客观下线,并在flags上打上SRI_O_DOWN标识,并对主服务器执行故障转移操作。
三、故障转移(主从切换流程)
大致流程上面介绍过,这里就详细介绍一下。
3.1 选举领头Sentinel
当一个主服务器被判断客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作,下面是选举领头Sentinel过程:
- 首先会发起一次选举:将current_epoch(集群纪元)加1,向其它监视该master的Sentinel发送拉票命令:SENTINEL is-master-down-by-addr命令,要求目标Sentinel将选票投给自己
- 目标Sentinel在接收到SENTINEL is-master-down-by-addr命令后,会判断自己是否已经在本次选举中投过票,如果没有则会将选票投给源Sentinel,最后回复leader和leader_epoch,代表自己所投的局部领头Sentinel的运行ID和配置纪元。
- 源Sentinel收到回复后,会检查回复中leader_epoch参数的值是否和自己的配置纪元相同,如果相同,源Sentinel会取leader_runid,如果这也相同,那么标识目标Sentinel将源Sentinel设置成了局部领头Sentinel。
- Sentinel中同样有自己的时间事件会被定期触发,当Sentinel状态为:SENTINEL_FAILOVER_STATE_WAIT_START,会触发选举的投票结果统计,如果某个Sentinel获得超过半数及以上的选票(>=voters/2+1),那么这个Sentinel将称为领头Sentinel。
- 如果在给定时限内,没有一个Sentinel成为领头Sentinel,那么会在一段时间后再次进行选举,直到出现领头Sentinel。
ps:因为领头 Sentinel 的产生需要半数以上 Sentinel 的支持,并且每个 Sentinel 在每个配置纪元里面只能投一次票 ,所以在一个配置纪元里面,只会出现一个领头 Sentinel 。
3.2 选出新的主服务器
在选举出领头Sentinel后,领头Sentinel将对已下线的主服务器执行故障转移操作。而故障转移操作的第一步要做的就是在已下线主服务器属下的所有从服务器中,挑选出一个状态良好、数据完整的从服务器,然后向这个从服务器发送SLAVEOF no one命令, 将这个从服务器转为主服务器。
领头Sentinel会将已下线的主服务下所有从服务器保存到一个列表里,然后按照以下规则逐一过滤:
- 删除列表中所有处于下线或者断线状态的从服务器:保证剩余从服务器都是正常在线的。
- 删除列表中所有最近5秒内没有回复过领头Sentinel的INFO命令的从服务器:保证剩余从服务器都是最近成功进行过通信的。
- 删除所有与已下线主服务器连接断开超过down-after-milliseconds*10毫秒的从服务器:保证剩余从服务器保存的数据都是比较新的。
- 之后,将根据从服务器的优先级对列表服务器进行排序,并选出优先级最高的从服务器。
- 如果优先级一样,则按照从服务器的复制偏移量,最大的当选(越大保存的数据越完整,可以参考上一篇文章主从复制)。
- 如果偏移量也一样,那就对运行ID排序,选出其中运行ID最小的从服务器。
被选出的从服务器发送SLAVEOF no one命令后,领头Sentinel会以每秒一次的频率,向被升级的从服务器发送INFO命令,并观察回复中的角色(role)信息,当role从原来的slave变为master时,从服务器就已经顺利升级为主服务器了。
3.3 修改从服务器的复制目标
当新的主服务器升级完成后,下一步走的就是让已下线主服务器下的所有从服务器去复制新的主服务器,这一操作主要用SLAVEOF <master_ip> <master_port>来实现。
3.4 将旧的主服务器变为从服务器
故障转移最后要做的是将已下线的主服务器设置为新的主服务器的从服务器,过程也很简单,就是当旧的主服务器再次上线时,Sentinel就会向他发送SLAVEOF命令,让它成为新的主服务器的从服务器。
四、优缺点
优点:
- 哨兵模式是基于主从模式的,解决可主从模式中master故障不可以自动切换故障的问题。
缺点:
- 是一种中心化的集群实现方案:始终只有一个Redis主机来接收和处理写请求,写操作受单机瓶颈影响。
- 集群里所有节点保存的都是全量数据,浪费内存空间,没有真正实现分布式存储。数据量过大时,主从同步严重影响master的性能。
- Redis主机宕机后,哨兵模式正在投票选举的情况之外,因为投票选举结束之前,谁也不知道主机和从机是谁,此时Redis也会开启保护机制,禁止写操作,直到选举出了新的Redis主机。
End:希望对大家有所帮助,如果有纰漏或者更好的想法,请您一定不要吝啬你的赐教🙋。