Redis-哨兵

概览

Sentinel(哨兵)是Redis高可用性解决方案:
由一个或多个哨兵实例组成的哨兵系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器

获取主服务器信息

哨兵默认会以十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息

通过分析主服务器返回的INFO命令回复,哨兵可以获取一下两方面的信息:

  • 关于主服务器本身的信息
    包括run_id域记录的服务器运行ID,以及role域记录的服务器角色
  • 关于主服务器属下所有从服务器的信息
    记录了从服务器的IP地址和端口号,哨兵无需用户提供从服务器的地址信息就可以发现从服务器

选举领头哨兵

当一个主服务器被判断为客观下线时,见识这个下线主服务器的各个哨兵会进行协商,选举出一个领头哨兵,并由领头哨兵对下线主服务器执行故障转移操作

以下是Redis选举领头哨兵的方法:

  • 所有在线的哨兵都有被选为领头哨兵的资格,换句话说,监视同一个主服务器的多个在线哨兵中的任意一个都有可能成为领头哨兵
  • 每次进行领头哨兵选举之后,不论选举是否成功,所有哨兵的配置纪元的值都会自增一次
  • 在一个配置纪元里面,所有哨兵都有一次将某个哨兵设置为局部领头哨兵的机会,并且局部领头一旦设置,在这个配置纪元里面就不能再更改
  • 每个发现主服务器进入客观下线的哨兵都会要求其他哨兵将自己设置为局部领头
  • 当一个源哨兵向另一个目标哨兵发送SENTINEL is-master-down-by-addr命令,并且命令中的runid参数不是*符号而是源哨兵的运行ID时,表示源哨兵要求目标哨兵将前者设置为后者的局部领头哨兵
  • 哨兵设置领头哨兵的规则是先到先得,最先向目标哨兵发送设置要求的源哨兵将成为目标哨兵的局部领头哨兵,而之后接收到的所有设置要求都会被目标哨兵拒绝
  • 目标哨兵在接收到SENTINEL is-master-down-by-addr命令之后将向源哨兵返回一条命令回复,回复中的leader_runid参数和leader_epoch参数分别记录了目标哨兵的局部领头哨兵的运行ID和配置纪元
  • 源哨兵在接收到目标哨兵返回的命令回复之后,会检查其中的leader_epoch参数值和自己的配置纪元是否相同,如果相同的话,那么源哨兵将继续取出回复中的leader_runid参数,如果leader_runuid参数的值和源哨兵的运行ID一致,那么表示目标哨兵将源哨兵设置为了局部哨兵
  • 如果有某个哨兵被半数以上的哨兵设置成了局部领头哨兵,那么这个哨兵成为领头哨兵
  • 因为哨兵的产生需要半数以上哨兵的支持,并且每个哨兵在背个配置纪元里面只能设置一次局部领头哨兵,所以在一个配置纪元里面只会出现一个领头哨兵
  • 在给定期限内如果没有一个哨兵被选举为领头哨兵,那么哥哥哨兵将在一段时间之后再次进行选举,直到选出领头哨兵为止

故障转移

在选举产生出领头哨兵之后,领头哨兵将对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤:

  1. 在已下线主服务器所辖所有从服务器里面,挑选出一个从服务器,并将其转换为主服务器
  2. 让已下线主服务器输下的所有从服务器改为新主服务器的从服务器
  3. 将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,他就会成为新的主服务器的从服务器

选出新的主服务器

大概规则就是挑选出在线的,复制偏移量最大的服务器,一样大就比较runID

修改从服务器的复制目标

即向从服务器发送SLAVEOF指令

将旧的主服务器变为从服务器

因为旧的主服务器已经下线,所以这种设置是保存在已下线旧主服务器对应的实例结构里面的,当就主服务器重新上线后,哨兵就会立即向他发送SLAVEOF命令

重点回顾

  • 哨兵值是一个运行在特殊模式下的Redis服务器,它使用了和普通模式不同的命令表,所以哨兵模式能使用的命令和普通的Redis服务器能够使用的命令不同
  • 哨兵会读入用户指定的配置文件,为每个要被检视的主服务器创建响应的实例结构,并创建连向主服务器的命令连接和订阅连接
  • 哨兵通过向主服务器发送INFO命令来获得主服务器属下所有从服务器的地址信息,并为这些从服务器创建相应的实力结构,以及连向这些从服务器的命令连接和订阅连接
  • 在一般情况下,哨兵以每十秒一次的频率向被监视的主服务器和从服务器发送INFO命令,当主服务器处于下线状态,或者哨兵正在对主服务器进行故障转移操作时,哨兵向从服务器发送INFO命令的频率会改为每秒一次
  • 对于监视同一个主服务器和从服务器的说个哨兵来说,它们会每两秒一次通过向被监视服务器的__sentinel__:hello频道发送消息来向其他哨兵宣告自己的存在
  • 每个哨兵也会从__sentinel__:hello频道中接受其他哨兵发来的信息,并根据这些信息为其他哨兵创建响应的实例结构以及命令连接
  • 哨兵只会与主服务器和从服务器创建命令连接和订阅连接,哨兵与哨兵之间只会创建命令连接
  • 哨兵会以每秒一次的频率向实例(包括主服务器,从服务器,其他哨兵)发送PING命令,并根据实例对PING命令的回复来判断实例是否在线,当一个实例在指定的市场中连续向哨兵发送无效回复时,哨兵会将这个实例判断为主观下线
  • 当哨兵将一个主服务器判断为主观下线时,它会向同样监视这个主服务器的其他哨兵进行询问,看他们是否同意这个主服务器已经进入主观下线的状态
  • 当哨兵收集到足够多的的主观下线投票之后,它会将主服务器判断为客观下线,并发起一次针对主服务器的故障转移操作