8.3 故障转移(failover)

当两台以上Redis形成主备关系,它们组成的集群就具备了一定的高可用性:当master故障时,slave可以成为新master,对外提供读写服务,这种运营机制称为failover。

剩下的问题在于:谁去发现master的故障做failover的决策呢?

一种方式是,保持一个daemon进程,监控着所有的master-salve节点,如图:

 

 上图,一个Redis集群里有一个master和两个slave,这个daemon进程监视着这三个节点。这种方式的问题在于:daemon作为单点,它本身的可用性无法保证。因此需要引入多daemon,如图:

 

上图,为了解决daemon单点问题,引入两个daemon进程,同时监视三个Redis节点。但是,多个daemon的引入虽然解决了可用性问题,但带来了一致性问题:多个daemon之间,如何就某个master是否可用达成一致?比如,daemon1和master网络不通,但是master和其他节点畅通,那么daemon1和daemon2观察到的master可用状态不同,那么如何决策此时master是否需要failover呢?

Redis的sentinel提供了一套多daemon间交互机制,解决故障发现、failover决策协商机制等问题,如图:

 

 上图中,多个daemon组成一个集群,称为sentinel集群,其中daemon也被称为sentinel节点。这些节点间通信、选举、协商,在master节点的故障发现、failover决策上表现出一致性。

8.3.1 sentiel间的相互感知

sentinel节点因为共同监视了同一个master节点从而相互关联了起来,一个新加入的sentinel节点需要和有相同监视的master的其他sentinel节点相互感知,方式如下:所有需要相互感知的sentinel都向他们共同的master节点上订阅相同channel:_sentinel_:hello,新加入的sentinel节点向这个channel发布一条消息(包含自己的信息),该channel的订阅者们就可以发现这个新的sentinel。随后新sentinel和已有的其他sentinel节点建立长连接。sentinel集群中所有节点两两连接,如图:

8.3.2 master的故障发现

sentinel节点通过定期向master发送心跳包判断其存活状态,称为PING。

一旦master没有正确响应,sentinel就将此master置为“主观不可用态”,其他sentinel还没有确定。如图:

 随后将“主观不可用态”发送给其他所有sentinel节点进行确认(即上图is-master-down-by-addr这条交互),当确认的节点数>=quorum(可配置)时,则判定该master为“客观不可用”,随后进入failover流程。

8.3.3 failover决策

master宕机时,可能多个sentinel同时发现此问题并交互确认了master达到了“客观不可用态”,同时打算发起failover。但是只能有一个sentinel节点作为failover的发起者,此时需要开始一个leader选举的过程,选择谁发起failover。

Redis的sentinel机制采用类似Raft协议实现这个选举算法:

  • sentinelState的epoch变量类似于raft协议中的term(选举回合)。
  • 每一个确认了master“客观不可用态”的sentinel节点都会向周围广播自己参选的请求。
  • 每个接收到参选请求的sentinel节点如果还没人向他发送过参选请求,它就将本选举回合的意向置为首个参选sentinel并回复它;如果已经在本回合表过意向了,则拒绝本回合内所有其他参选请求,并将已有意向回复给参选sentinel。
  • 每一个发送参选请求的sentinel节点如果收到了超过一半的意向同意某个参选sentinel(可能是自己),则确定该sentinel为leader;如果本回合持续足够长时间没能选出leader,则开启下一回合。

leadersentinel确定后,从master所有的slave中依据一定的规则选取一个作为新master,告知其他slave连接这个新master。

posted @ 2020-05-05 01:21  vvf  阅读(552)  评论(0编辑  收藏  举报