前面提到了,Sentinel如何将一台服务器认定为客观下线,下面就来看,对于客观下线的服务器,Sentinel是怎么处理的
选举领头的Sentinel
当一台Sentinel认为被监视的服务器客观下线了之后,就会与监视这个下线主服务器的各个Sentinel进行协商,选举出一个领头的Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作(所以前面提到的领头Sentinel其实就是去完成故障转移操作的)
下面说一下这个选举规则吧
- 所有在线的Sentinel都有被选为领头Sentinel的资格,即监视同一个主服务器的多个在线Sentinel中的任意一个都有可能称为领头Sentinel
- 每次进行领头Sentinel选举之后,不论此时选举是否成功,所有Sentinel的配置纪元(epoch)的值都会进行自增一次,实际上Sentinel的epoch纪元就是一个计数器,用来记录该Sentinel参与了多少次选举(可以用来表示Sentinel的"熟练",与新来的Sentinel不一样,不过这个epoch现在所说的投票选举没什么影响作用,单纯用来鉴别Sentinel的,我猜测可能是runid比较会比较慢,所以使用epoch来加以辅助)
- Sentinel对于该领头都是十分愿意去当的,每个发现主服务器进入客观下线的Sentinel(发现客观下线的Sentinel也是去发送SENTINEL is-master-down-by-addr命令,只不过runid改成了自己的)都会要求其他Sentinel将自己设置为局部领头Sentinel(即相当于让他们投自己的票)
- 当一个目标Sentinel接收到源Sentinel发送的SENTINEL is-master-down-by-addr命令之后,会去对比runid属性(如果为*代表是有服务器被判定为主观下线了,如果不是,就代表有Sentinel想要目标Sentinel将自己设置为局部领头Sentinel)。
- 设置局部领头Sentinel的规则则是先到先当,最先向目标Sentinel发送的源Sentinel会被设为局部领头,然后之后收到的目标Sentinel接收到的所有设置领头Sentinel要求都会被拒绝(即下面的每一次配置纪元只能修改一次)。
- 在一个配置纪元里面(即epoch等于某一个值时),每个Sentinel都只有一次设置局部领头Sentinel的机会,只要设置了,就不能再设置了(除非当前这次选举不成功,配置纪元发生变化,才可以进行再设置)
- 同时,目标Sentinel还会像源Sentinel发送其设置领头Sentinel的结果,回复中有leader_epoch参数和leader_runid参数,源Sentinel会先用自己的epoch参数比较leader_epoch参数,如果相同,再用leader_runid参数比较自己的runid,如果一致,表明目标Sentinel将自己设置为了领头Sentinel
- 当某个Sentinel统计选举自己当局部领头Sentinel的数量,并且统计结果超过了Sentinel组成的Sentinels的半数,那么这个Sentinel就会成为领头Sentinel
- 一个配置纪元就代表每一次选举,因为一个配置纪元只能设置一个局部领头Sentinel,如果当前纪元没法选出领头Sentinel,配置纪元就会加一,然后进行下一轮选举
- 如果在指定时间内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将会在一段时间之后再次选举,直到选出Sentinel为止
故障转移
经过上面的选举,现在已经选出领头Sentinel去进行故障转移的操作了。
故障转移操作包括下面三个步骤
- 在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并且将其转换为新的主服务器
- 让已下线主服务器属下的所有从服务器去复制新的主服务器
- 将已下线的主服务器设置为新的主服务器的从服务器,当这个已下线的主服务器重新上线时,它就会成为新的主服务器的从服务器
挑选新的主服务器
领头Sentinel要去做的第一件事,就是从存活的从服务器中选举出一个去当主服务器,而且要挑选出一个状态良好、数据完整的从服务器,然后通过与该从服务器建立的命令连接发送SLAVEOF no one命令,让其不再去复制原来的主服务器,并且将这个从服务器转换为主服务器
现在问题来了,新的主服务器是怎么挑选出来的?
领头Sentinel首先会从客观下线的服务器实例那里取出他的slave字典,然后保存在一个列表里面,然后按照下面的规则对列表进行过滤
- 删除列表中所有处于下线或者断线状态的从服务器,保证列表里面的从服务器都是正常在线的(也是通过ping命令去实现)。
- 删除列表中所有最近5秒内没有回复过领头Sentinel的INFO命令的从服务器,保证列表里面剩余的从服务器都是最近成功进行过通信的。
- 删除所有与已下线主服务器连接断开超过down-after-milliseconds*10毫秒的从服务器,保证列表里面剩余的从服务器都是最近与以下线的主服务器进行过通信的,即里面的数据是比较新的
- 如果前面3条规则还没有选出从服务器,那么就会根据从服务器的自己维持的一个复制偏移量offset去进行判断(回看复制那篇文章),并选出其中复制偏移量最大的从服务器去成为新的主服务器
- 最后,如果仍然没有选出,那么领头Sentinel将按照运行ID对剩余的从服务器进行排序,并选出其中运行ID最小的从服务器(也就是对应越早使用的从服务器)
修改从服务器的复制目标
当新的主服务器出现之后,领头Sentinel下一步要做的就是,让新的主服务器不再复制原来的主服务器,并且让已经下线的主服务器属下的所有从服务器去复制新的主服务器,这都可以使用slaveof命令去实现(通过命令连接去发送)。
- 给被推选出新的主服务器的从服务器发送slaveof no one命令
- 给其余从服务器发送slave of <新的主服务器ip> <新的主服务器port>命令

将旧的主服务器变为从服务器
故障转移最后的操作就是,针对已下线的主服务器进行处理(因为主服务器后面可能会重新连接)
当已下线的主服务器重新上线时,Sentinel会根据之前保存的实例(并且这个实例已经被修改成是从服务器类型,绑定上了新的主服务器的ip地址和端口)去识别他,如果匹配,就给他发送slaveof命令,让他成为新的主服务器的从服务器。
本文介绍Redis Sentinel机制中故障转移的过程,包括选举领头Sentinel、选择新的主服务器、调整从服务器复制目标及将旧主服务器转为从服务器等关键步骤。
1万+

被折叠的 条评论
为什么被折叠?



