分布式Redis深度历险-Sentinel

本文为分布式Redis深度历险系列的第二篇,主要内容为Redis的Sentinel功能。 更多文章见我的博客:github.com/farmerjohng…git

上一篇介绍了Redis的主从服务器之间是如何同步数据的。试想下,在一主一从或一主多从的结构下,若是主服务器挂了,整个集群就不可用了,单点问题并无解决。Redis使用Sentinel解决该问题,保障集群的高可用。github

如何保障集群高可用

保障集群高可用,要具有以下能力:redis

  • 能监测服务器的状态,当主服务器不可用时,能及时发现
  • 当主服务器不可用时,选择一台最合适的从服务器替代原有主服务器
  • 存储相同数据的主服务器同一时刻只有一台

要实现上述功能,最直观的作法就是,使用一台监控服务器来监视Redis 服务器的状态。算法

image

监控服务器和主从服务器间维护一个心跳链接,当超出必定时间没有收到主服务器心跳时,主服务器就会被标记为下线,而后通知从服务器上线成为主服务器。服务器

image

当原来的主服务器上线后,监控服务器会将其转换为从服务器。 分布式

image

按照上述流程彷佛解决了集群高可用的问题,但彷佛有哪里不对:若是监控服务器出了问题怎么办?咱们能够在加上一个从监控服务器,当主服务器不可用的时候顶上。 3d

image

但问题是谁来监控'监控服务器'呢?子子孙孙无穷尽也。。code

先把疑问放在一旁,先来看下Redis Sentinel集群的实现cdn

Sentinel

和上一小节的想法同样,Redis经过增长额外的Sentinel服务器来监控数据服务器,Sentinel会与全部的主服务器和从服务器保存链接,用以监听服务器状态以及向服务器下达命令。server

image

Sentinel自己是一个特殊状态的Redis服务器,启动命令: redis-server /xxx/sentinel.conf --sentinel,sentinel模式下的启动流程与普通redis server是不同的,好比说不会去加载RDB文件以及AOF文件,自己也不会存储业务数据。

与主服务器创建链接

Sentinel启动后,会与配置文件中提供的全部主服务器创建两个链接,一个是命令链接,一个是订阅链接。

命令链接用于向服务器发送命令。

订阅链接则是用于订阅服务器的_sentinel_:hello频道,用于获取其余Sentinel信息,下文会详细说。

获取主服务器信息

Sentinel会以必定频率向主服务器发送Info命令获取信息,包括主服务器自身的信息好比说服务器id等,以及对应的从服务器信息,包括ip和port。Sentinel会根据info命令返回的信息更新本身保存的服务器信息,并会与从服务器创建链接。

获取从服务器信息

与和主服务器的交互类似,Sentinel也会以必定频率经过Info命令获取从服务器信息,包括:从服务器ID,从服务器与主服务器的链接状态,从服务器的优先级,从服务器的复制偏移等等。

向服务器订阅和发布消息

如何保障集群高可用小节留下了一个疑问:用如何保证监视服务器的高可用? 在这里咱们能够先给出简单回答:用一个监视服务器集群(也就是Sentinel集群)。如何实现,如何保证监视服务器的一致性暂且先不说,咱们只要记住须要用若干台Sentinel来保障高可用,那一个Sentinel是如何感知其余的Sentinel的呢?

前面说过,Sentinel在与服务器创建链接时,会创建两个链接,其中一个是订阅链接。Sentinel会定时的经过订阅链接向_sentinel_:hello频道频道发送消息(对Redis发布订阅功能不太了解的同窗能够去去了解下),其中包括:

  • Sentinel自己的信息,如ip地址、端口号、配置纪元(见下文)等
  • Sentinel监视的主服务器的信息,包括ip、端口、配置纪元(见下文)等

同时,Sentinel也会订阅_sentinel_:hello频道的消息,也就是说Sentinel即向该频道发布消息,又从该频道订阅消息。

image

Sentinel有一个字典对象sentinels,保存着监视同一主服务器的其余全部Sentinel服务器,当一个Sentinel接收到来自_sentinel_:hello频道的消息时,会先比较发送该消息的是否是本身,若是是则忽略,不然将更新sentinels中的内容,并对新的Sentinel创建链接。

主观下线

Sentinel默认会以每秒一次的频率向全部创建链接的服务器(主服务器,从服务器,Sentinel服务器)发送PING命令,若是在down-after-milliseconds内都没有收到有效回复,Sentinel会将该服务器标记为主观下线,表明该Sentinel认为这台服务器已经下线了。须要注意的是不一样Sentinel的down-after-milliseconds是能够不一样的。

客观下线

为了确保服务器真的已经下线,当Sentinel将某个服务器标记为主观下线后,它会向其余的Sentinel实例发送Sentinel is-master-down-by-addr命令,接收到该命令的Sentinel实例会回复主服务器的状态,表明该Sentinel对该主服务器的链接状况。

Sentinel会统计发出的全部Sentinel is-master-down-by-addr命令的回复,并统计赞成将主服务器下线的数量,若是该数量超出了某个阈值,就会将该主服务器标记为客观下线。

选举领头Sentinel

当Sentinel将一个主服务器标记为客观下线后,监视该服务器的各个Sentinel会经过Raft算法进行协商,选举出一个领头的Sentinel。 建议你先看Raft算法的基础知识,再来看下文。

规则:

  • 全部的Sentinel都有可能成为领头Sentinel的资格
  • 每次选举后,不管有没有选出领头Sentinel,配置纪元都会+1
  • 在某个纪元里,每一个Sentinel都有为投票的机会
  • 咱们称要求其余人选举本身的Sentinel称为源Sentinel,将被要求投票的Sentinel称为目标Sentinel
  • 每一个发现主服务器被标记为客观下线且尚未被其余Sentinel要求投票的Sentinel都会要求其余Sentinel将本身设置为头
  • 目标Sentinel在一个配置纪元里,一旦为某个Sentinel(也多是它本身)投票后,对于以后收到的要求投票的命令,将拒绝
  • 目标Sentinel对于要求投票的命令将回复本身选举的Sentinel的id以及当前配置纪元
  • 源Sentinel在接收到要求投票的回复后:若是回复的配置纪元与本身的相同,则再检测目标Sentinel选举的头Sentinel是否是本身
  • 若是某个Sentinel被半数以上的Sentinel设置成了领头Sentinel,那它将称为领头Sentinel
  • 一个配置纪元只会选出一个头(由于一个头须要半数以上的支持)
  • 若是在给定时间内,尚未选出头,则过段时间再次选举(配置纪元会+1)

还记得咱们在文章开头提出的如何保证Redis服务器高可用的问题吗? 答案就是使用若干台Sentinel服务器,经过Raft一致性算法来保障集群的高可用,只要Sentinel服务器有一半以上的节点都正常,那集群就是可用的。

故障转移

领头Sentinel将会进行如下3个步骤进行故障转移:

1.在已下线主服务器的全部从服务器中,挑选出一个做为新的主服务器

2.将其余从服务器的主服务器设置成新的

3.将已下线的主服务器的role改为从服务器,并将其主服务器设置成新的,当该服务器从新上线后,就会一个从服务器的角色继续工做

第一步中挑选新的主服务器的规则以下:

1.过滤掉全部已下线的从服务器

2.过滤掉最近5秒没有回复过Sentinel命令的从服务器

3.过滤掉与原主服务器断开时间超过down-after-milliseconds*10的从服务器

4.根据从服务器的优先级进行排序,选择优先级最高的那个

5.若是有多个从服务器优先级相同,则选取复制偏移量最大的那个

6.若是上一步的服务器还有多个,则选取id最小的那个

相关文章
相关标签/搜索