当前位置: 首页 > 科技观察

说说Redis为什么有哨兵?

时间:2023-03-21 19:01:32 科技观察

大纲为什么要有哨兵机制?在Redis的主从架构中,由于主从模式是读写分离,如果主节点(master)挂了,就没有主节点来服务客户端的写操作请求。也没有主节点与从节点(slave)同步数据。如果主节点宕机,如果要恢复服务,需要手动干预,选择一个“从节点”切换到“主节点”,然后让其他从节点指向新的主节点,并且还需要通知上游连接Redis的主节点,更新其配置中主节点的IP地址为“新主节点”的IP地址。这还不算太“聪明”。如果有一个节点可以监控“主节点”的状态,当它发现主节点宕机时,会自动将一个“从节点”切换为“主节点”,这样可以为我们省去很多事!Redis在2.8版本之后提供的Sentinel机制,用于实现主从节点故障转移。它会监控master节点是否存活,如果发现master节点挂了,会选举一个slave节点切换到master节点,并将新master的相关信息通知slave节点和client节点。哨兵机制是如何工作的?哨兵实际上是一个运行在特殊模式下的Redis进程,所以它也是一个节点。从名字“Sentinel”也可以看出,它相当于一个“观察者节点”,观察的对象是主从节点。当然,不仅仅是观察那么简单。当它观察到异常情况时,它会采取一些“行动”来修复异常状态。哨兵节点主要负责三件事:监控、选举和通知。哨兵的职责那么,我们需要学习这三个东西:哨兵节点是如何监控节点的?如何判断主节点是否真的有故障?根据什么规则选择从节点切换到主节点?如何切换新的主节点?如何将节点的相关信息通知从节点和客户端?如何判断master节点真的有故障?哨兵会周期性的向所有主从节点发送PING命令。当主从节点收到PING命令时,它会向哨兵发送响应命令,以便它们判断自己是否正常运行。Sentry监控主从节点。如果主节点或从节点在规定的时间内没有响应哨兵的PING命令,哨兵就会将他们标记为“主观下线”。这个“规定时间”是由配置项down-after-milliseconds参数设置的,单位是毫秒。主观下线?线下有目标吗?是的,客观离线仅适用于主节点。之所以为“主节点”设计“主观下线”和“客观下线”两种状态,是因为有可能“主节点”实际上并没有故障,可能是因为主节点的系统压力节点比较高或者网络发送拥塞导致主节点无法在规定时间内响应哨兵的PING命令。所以为了减少误判的情况,Sentinel在部署的时候不会只部署一个节点,而是将多个节点部署成一个sentinel集群(部署一个sentinel集群至少需要三台机器),通过多个sentinel节点进行判断,可以避免单个sentinel因为自身网络不好而误判master节点下线的情况。同时,多个Sentinels网络同时不稳定的概率很小,一起做决策,也可以降低误判率。它如何确定主节点“客观离线”?当一个哨兵判断主节点“主观下线”时,它会向其他哨兵发出命令。主节点的网络状态,以赞成票或拒绝票响应。当Sentinel的投票数达到Sentinel配置文件中quorum配置项设置的值时,master节点将被Sentinel标记为“客观下线”。比如有3个Sentinels,quorum配置为2,那么一个Sentinel需要2个赞成票才能将master节点标记为“客观下线”。2个赞成票包括哨兵自己的赞成票和另外两个哨兵的赞成票。PS:quorum的值一般设置为哨兵数量的1/2加1,比如有3个哨兵就设置2。当哨兵判断主节点客观下线后,哨兵会开始从多个“从节点”中选择一个从节点作为新的主节点。如何选择新的主节点?这么多“从节点”,选择哪个从节点作为新的主节点呢?随机方法好吗?随机方式实现起来非常简单,但是如果选择一个网络状态不好的从节点作为新的主节点,那么在不久的将来可能会进行另一次主从故障切换。因此,我们首先要过滤掉网络状态不好的从节点。先过滤掉掉线的从节点,再过滤掉过去网络连接状态不好的从节点。如何判断从节点之前的网络连接状态不好呢?Redis有个配置项叫down-after-milliseconds*10,它的down-after-milliseconds就是主从节点断开连接的最大连接超时时间。如果在down-after-milliseconds毫秒内,主从节点没有通过网络连接,我们可以认为主从节点断开了。如果掉线次数超过10次,说明从节点网络状况不好,不适合做新的主节点。至此,我们已经过滤掉了网络状态不好的从节点,接下来我们将对所有从节点进行三轮检查:优先级、复制进度、ID号。在进行每一轮调查时,谁先获胜的从节点将被选为新的主节点。第一轮检查:哨兵会先按照slave节点的优先级排序,优先级越低,排名越高,第二轮检查:如果优先级相同,检查复制的下标,哪个slave“主节点”如果收到的复制数据多了,先到哪一个。第三轮考察:如果优先级和下标相同,则选择从节点ID较小的。第一轮调查:优先级最高的从节点获胜。Redis有一个配置项叫做slave-priority,可以为slave节点设置优先级。每个从节点的服务器配置不一定相同,我们可以根据服务器性能配置设置从节点的优先级。例如,如果“A从节点”的物理内存是所有从节点中最大的,那么我们就可以将“A从节点”的优先级设置为最高。这样sentinel在进行第一轮考虑时,优先级最高的A从节点将首先获胜,然后成为新的主节点。第二轮调查:复制进度最高的从节点获胜。如果在第一轮检查中发现有两个优先级最高的从节点,则进行第二轮检查,比较这两个从节点的复制进度。.复制进度如何?在主从架构中,主节点会将写操作同步到从节点。在这个过程中,主节点会使用master_repl_offset记录最近一次写操作在repl_backlog_buffer中的位置,而从节点会使用slave_repl_offset这个值记录当前的复制进度。如果一个slave节点的slave_repl_offset与master_repl_offset最接近,说明它的复制进度最先进,可以选为新的master节点。第三轮检验:ID号较小的从节点获胜。如果在第二轮检查中发现有两个从节点具有相同的优先级和复制进度,则进行第三轮检查比较这两个从节点。ID号小的从节点获胜。什么是身份证号码?每个从节点都有一个编号,就是ID号,用来唯一标识从节点。至此,选主的事情总算是结束了。给大家简单总结一下:过滤掉已经下线的slave节点;过滤掉历史网络连接状态不佳的从节点;对剩下的从节点进行三轮检查:优先级、复制进度、ID号。在每一轮调查中,如果发现一个获胜的从节点,它将被用作新的主节点。哪个哨兵将执行主从故障转移?前面提到,为了更“客观”地判断主节点的故障,一般不会只通过单个sentinel的检测结果来判断,而是通过多个sentinel来判断,这样可以减少错误。判断概率,所以哨兵是以哨兵簇的形式存在的。在选择了将成为主节点的从节点之后,Sentinel集群中的哪个节点将执行主从故障转移?所以这时候也需要在Sentinel集群中选择一个leeder,让Leader进行主从切换。选举Leeder的过程实际上是一个投票过程。在投票开始之前,必须有一个“候选人”。那么谁会是候选人呢?哪个sentinel节点判断master节点“客观下线”,这个sentinel节点就是candidate,所谓candidate就是想当Leader的sentinel。例如,假设有三个哨兵。当SentinelA首先判断master节点“主观下线”时,会向其他实例发送is-master-down-by-addr命令。然后,其他哨兵将根据他们与主节点的网络连接,通过投票赞成或拒绝投票来做出回应。当SentinelA收到赞成票数达到Sentinel配置文件中quorum配置项中设置的值时,就会将master节点标记为“客观下线”,此时的SentinelA就是Leader候选者。候选人如何选举成为Leader?Candidates向其他Sentinels发送命令,表明自己想成为Leader进行主从切换,并让所有其他Sentinels投票。每个哨兵只有一次投票机会。如果用完,则不能参与投票。它可以为自己或他人投票,但只有候选人可以为自己投票。那么在投票过程中,任何“候选人”都必须满足两个条件:第一,获得半数以上的赞成票;其次,你获得的投票数也必须大于或等于sentinel配置文件中的quorum值。Forexample,supposethereare3sentinelnodesandthequorumissetto2,thenanysentinelwhowantstobecomealeadercanbeelectedaslongashegets2yesvotes.如果不满足条件,则需要重新选举。这时候有同学会问,如果在某个时间点,只有两个sentinel节点判断master节点客观下线,那么这个时候会有两个candidate?这个时候,怎么决定谁是Leader呢?每个候选人都会先为自己投票,然后再向其他哨兵发起投票请求。如果选民先收到“候选人A”的投票请求,他会先投票给它。如果投票人用尽投票机会,收到“候选人B”的投票请求,则拒绝投票。此时,候选人A首先满足以上两个条件,因此“候选人A”将被选举为leader。为什么至少有3个哨兵节点?如果sentinel集群中只有2个sentinel节点,一个哨兵要想成功成为leader,必须获得2票,而不是1票。因此,如果哨兵集群中有一个哨兵死亡,那么就只剩下一个哨兵了。如果哨兵要成为leader,那么票数不能达到2票,就不能成功成为leader。这个时候是不可能Master-slave节点切换的。因此,通常我们会配置至少3个sentinel节点。这个时候如果哨兵丛中有一个哨兵死亡,那么还剩下两个哨兵。如果这个哨兵要成为leader,此时还有机会达到2票,所以选举还是可以成功的,不会导致无法进行主从节点切换。当然你要问了,如果3个sentinel节点有2个挂了怎么办?这时候就需要人为干预,或者增加更多的sentinel节点。还有一个问题,Redis1master4slave,5sentinel,quorum设置为3,如果2个sentinel失效,当master节点宕机时,sentry能否判断master节点“客观下线”?可以自动切换吗?Sentinel集群可以判断主节点“客观离线”。哨兵集群中还剩下3个哨兵。当一个哨兵判断主节点“主观下线”,向其他2个哨兵询问时,有可能获得3票赞成。这个时候就已经达到quorum的值了。因此,Sentinel集群可以判断master节点“客观离线”。Sentinel集群可以完成主从切换。当一个Sentinel将master节点标记为“客观下线”时,就会进行选举Leader的过程,因为Sentinel集群中还剩下3个Sentinel,那么仍然可以获得一半以上(5/2+1=3)票数,也达到quorum值,满足选举leader的两个条件,所以才能选举成功,这样sentinel集群才能完成主从切换。但是如果quorum设置为2,情况就不一样了。此时sentinel集群仍然可以判断master节点“客观下线”,但是sentinel无法完成主从切换,可以自行推导。所以quorum的值建议设置为sentinel数的一半加1,比如3个sentinel设置2,5个sentinel设置3,sentinel节点数应该是奇数。如何通知客户端新主节点的信息?经过前面一系列的操作,哨兵集群终于完成了主从故障迁移,那么如何通知客户端新主节点的信息呢?这主要是通过Redis的publisher/Subscriber机制来实现的。每个哨兵节点都提供了发布/订阅机制,客户端可以订阅来自哨兵的消息。比如客户端订阅主从切换的事件。当sentinel选出新的主节点时,会发布新主节点的IP地址和端口信息。这时候客户端就可以接收到这个信息,然后用这个里面新的主节点的IP地址和端口进行通信。哨兵集群是如何组成的?前面提到了Redis的发布者/订阅者机制,所以不得不提哨兵集群的构成,因为它也是用到了这个技术。刚开始搭建sentinel集群的时候,我当时很惊讶。因为在配置Sentinel信息的时候,只需要填写以下参数,设置master节点的名称,master节点的IP地址和端口号,以及quorum值。sentinelmonitor其他sentinel节点信息不用填写。我很好奇他们是如何感知对方的,又是如何形成哨兵集群的?后来才知道,Sentinel节点是通过Redis的发布/订阅机制来相互发现的。在主从集群中,master节点上有一个名为__sentinel__:hello的channel,不同的sentinel通过这个channel相互发现和通信。下图中,哨兵A将自己的IP地址和端口信息发布到__sentinel__:hello频道,哨兵B和哨兵C订阅了这个频道。那么此时哨兵B和哨兵C就可以直接从这个通道中获取到哨兵A的IP地址和端口号。然后,SentinelB和C就可以与SentinelA建立网络连接。这样,SentinelB和C也可以建立网络连接,这样就形成了一个Sentinel集群。哨兵集群会监控“从节点”的运行状态,那么哨兵集群是如何知道“从节点”的信息的呢?主节点知道所有“从节点”的信息,因此sentinel会向主节点发送INFO命令,从从节点获取所有“从节点”的信息。如下图所示,SentinelB向主节点发送INFO命令。主节点收到命令后,会将从节点列表返回给哨兵。然后,Sentinel可以根据从节点列表中的连接信息与各个从节点建立连接,并持续监控这个连接上的从节点。哨兵A和哨兵C可以通过相同的方法与从节点建立连接。正式通过Redis的发布者/订阅者机制,Sentinels可以相互感知,进而形成一个集群。同时,Sentinels通过INFO命令获取主节点中所有从节点的连接信息,从而与从节点建立连接,并进行监控。参考资料:《Redis 核心技术与实战》《Redis 设计与实现》总结了Redis在2.8版本之后提供的Sentinel机制。它的作用是实现自动主从故障转移。它会监控master节点是否存活,如果发现master节点挂了,会选举一个slave节点切换到master节点,并将新master的相关信息通知slave节点和client节点。哨兵一般部署在集群中,至少需要3个哨兵节点。Sentinel集群主要负责三件事:监控、master选举、通知。通过Redis的发布者/订阅者机制,哨兵节点可以相互感知,相互连接,进而形成哨兵集群。同时sentinel通过INFO命令获取master节点中slave节点的所有连接信息,从而可以与slave节点进行连接和监听。哨兵集群会通过投票的方式来决定主节点是否“客观下线”。如果确定主节点客观下线,则将选择所有“从节点”中的一个作为新的主节点。选择规则有以下步骤:过滤掉已经下线的从节点;过滤掉历史网络连接状态不佳的从节点;对剩下的从节点进行三轮检查:优先级、复制进度、ID号。在每一轮调查中,如果发现一个获胜的从节点,它将被用作新的主节点。选择从节点后,需要从Sentinel集群中选择一个leader进行主从切换。选举leader的过程也是一个投票的过程。任何一个哨兵节点想要成为leader,都必须满足两个条件:第一,获得半数以上的赞成票;其次,它得到的票数必须大于等于哨兵配置文件中的quorum值。Leader哨兵节点选出后,进行主从切换。主从切换完成后,通过Redis发布/订阅机制通知客户端新主节点的IP地址和端口。