主从架构下的Redis高可用

什么是主从复制?

主从复制是指将一台主服务器的数据,通过传输链路(网络或管道等)复制到其他从服务器的过程。前者称为主节点(master),后者称为从节点(slave)。

主从复制有什么好处? 

  • 读写分离:这种架构下可以用来实现读写分离。主节点进行写操作,从节点进行读操作,可以提高服务器的负载能力,同时可以灵活应对需求的各种变化,在需要时添加或减少从节点,从而最大限度的充分利用资源。
  • 负载均衡:在主从复制的基础上,配合读写分离,分担服务器负载。尤其是在写少读多的情况下,通过多个从节点分担读的负载,从而大大提高服务器的并发量。
  • 数据冗余:这种架构实现了数据的热备份,是持久化之外的另外一种数据冗余方式。
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现数据的快速故障恢复。
  • 高可用性基石:主从复制是集群和 Sentinel 能够实施的基础,是Redis 高可用的基石。

主从架构下如何实现Redis高可用?

当两台以上的 Redis 实例形成了主备关系,他们组成的集群就具备了一定的高可用性:当master故障时,slave可以成为新的master,对外提供读写服务,我们把这种机制成为 failover。那么还有一个问题:谁去发现master的故障做failover 的决策呢? 

 方案一:保持一个daemon进程,监控着所有的master-slave 节点,如下图所示:

主从架构下的Redis高可用

     很明显,这种方式的问题在于:daemon作为单点,它本身的可用性无法保证。

方案二: 引入多daemon节点,如下图所示:

主从架构下的Redis高可用

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

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

主从架构下的Redis高可用

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

  • sentinel 间的相互感知

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

主从架构下的Redis高可用

  • master故障发现

      sentinel 节点通过定期的向master 发送心跳包判断其存活状态,称为PING。一旦发现master 没有正确的响应,sentinel 将此master 置为“主观不可用状态”,所谓主观,是因为“master不可用”这个判定尚未得到其他的sentinel节点的确认。如下图所示: 

主从架构下的Redis高可用

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

  • failover决策

      当一台master真正宕机后,可能多个sentinel节点同时发现了此问题并通过交互确认了相互的“主观不可用态”猜想,同时达到“客观不可用态”,同时打算发起failover。但是最终只能有一个sentinel节点作为failover的发起者,此时需要开始一个Leader选举的过程,选择谁来发起failover。

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

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

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