转载——Redis高可用原理,这下能看懂了吧!(作者:codedump)

前言:Redis是被广泛使用的基础软件之一,对于架构师和运维人员来说,了解redis的高可用方案和原理是必备的基础知识。

作者简介:codedump.info 博主,多年从事互联网服务器后台开发工作。可访问作者博客 https://www.codedump.info 更多文章。

我是一个字一个字打下来的,就是为了加深印象,这篇文章深入浅出,很多原理解释的很透彻。以下是正文。

Redis为了实现高可用采用了如下两个方式:

  1. 主从复制数据
  2. 采用哨兵监控数据节点的运行情况,一旦主节点出现问题,则由从节点顶上继续服务。

主从复制

       Redis中复制主节点有全量复制和部分复制两种。

旧版本全量复制的实现:

  

全量复制使用Sync命令来实现,其流程是:

  1. 从服务器向主服务器发送Sync命令。
  2. 主服务器在收到Sync命令之后,调用Bigsave命令生成RDB文件,将这个文件同步给从服务器,这样的服务器载入这个RDB文件之后,状态就会和主服务器执行Bigsave命令时一致。
  3. 主服务器将保存在命令缓冲区中的写命令同步给从服务器,从服务器执行这些命令,这样的从服务器的状态就跟主服务器一致了。

旧版本全量复制功能,其最大的问题就是从服务器断线重连时,即便在从服务器上已经有部分数据了,也需要进行全量复制,这样做的效率很低,于是新版本的Redis也做了部分改进。

 

新版本全量复制功能的实现

       新版本Redis使用Psync命令代替Sync命令,该命令既可以实现全量同步,也可以实现部分同步。

 

复制偏移量

 

执行复制的双方,主从服务器,分别会维护一个复制偏移量。

  1. 主服务器每次向从服务器同步了N字节数据后,将修改自己的复制偏移量加N。
  2. 从服务器每次向主服务器同步了N字节数据后,将修改自己的复制偏移量加N。

 

复制及压缓冲区

  

主服务器内部维护了一个固定长度的先进先出队列作为复制积压缓冲区,其默认大小为1M。

 

在主服务器进行命令传播时,不仅会将命令同步到从服务器,还会将写命令写入到复制积压缓冲区。

 

服务器运行ID

      

       每个Redis服务器都有其运行ID,运行ID在服务器启动时自动生成,主服务器会将自己的运行ID发给从服务器,而从服务器会将主服务器的运行ID保存起来。

 

从服务器Redis断线重连之后进行同步时,就是根据运行ID来判断同步的进度:

  1. 如果从服务器上面保存的主服务器运行ID与当前主服务器运行ID一致,则认为这一次断线重新连接的是之前的主服务器,主服务器可以继续尝试部分同步操作。
  2. 如果前后两次的主服务器ID不同,则进行全量复制。

 

Psync命令流程

 

有了前面的准备,现在开始分析Psync命令的流程:

  1. 如果从服务器之前没有复制过任何主服务器,或者之前执行过Slave no one命令,那么从服务器就会向主服务发送psync ? -1命令,请求主服务器进行全量同步。
  2. 否则,前面从服务器已经同步过部分数据,那么从服务器向主服务器发送psync <runid> <offset>命令,其中runid是主服务器运行时ID,offset是当前从服务器的复制偏移量。

      

前面两种情况主服务器收到psync命令之后,会出现以下三种可能:

  1. Redis使用一组哨兵(Sentinel)来监控主从服务节点的可用性;
  2. 一旦发现Redis主节点失效,将选出一个哨兵作为节点领导者(Leader)。
  3. 哨兵领导者再从剩余的Redis从节点选出一个Redis节点作为新的主节点继续对外服务。

 

以上将Redis节点分为两类:

  1. 哨兵(Sentinel)节点:负责监控节点的运行情况;
  2. 数据节点:即正常服务客户端请求的Redis节点,有主从之分。

 

以上是大体流程,这个流程需要解决以下几个问题:

  1. 如何对redis节点进行监控?
  2. 如何确定一个Redis节点失效?
  3. 如何选出一个哨兵Leader节点?
  4. 哨兵节点选出一个新的Redis主节点的依据是什么?

 

 

三个监控任务

       哨兵节点通过三个定时监控任务监控Redis数据节点的服务可用性。

  1. info命令

每隔10秒,每个哨兵节点都会向Redis主从数据节点发送info命令,获取新的拓扑结构信息。

 

Redis拓扑结构信息包括了:

  1. 本节点角色:主或从
  2. 主从节点的地址或者端口信息。

这样,info命令就能从主从Redis节点获取节点信息,因此那些后续才加入的从节点信息不需要显示配置就能够感知。

 

2、向_sentinel_:hello频道同步信息

       每隔两秒,每个哨兵节点将会向Redis数据节点的_sentinel_:hello频道同步自身得到的主从节点信息以及当前哨兵节点的信息。

       由于其他哨兵节点也订阅了这个频道,因此这个操作可以交换哨兵节点之间关于主从节点以及哨兵节点的信息。

  

 

这一操作实际上完成两件事

  1. 发现新的哨兵节点:如果有新的哨兵节点加入,此时保存下来这个新哨兵节点的信息,后续与新哨兵节点建立连接。
  2. 交换主节点的状态信息,作为后续客观判断主节点下线的依据。

 

 

3、向主节点做心跳探测

  

       每隔一秒,每个哨兵节点向主从数据节点以及其他sentinel节点发送ping命令做心跳检测,这个心跳检测是后续主观判断Redis主节点下线的依据。

 

 

主观下线和客观下线

1、主观下线

上面三个监控任务中的第三个探测心跳任务,如果在配置的down-after-millisenconds之后没有收到有效回复,那么就认为该数据节点“主观下线(sdown)”。

 

为什么称为主观下线?因为在一个分布式系统中,有多个机器在一起联动工作,网络可能出现各种状况,仅凭一个节点的判断还足以证明该节点已经下线了,这就需要后面的“客观下线”。

2、客观下线

当一个哨兵节点认为主节点主观下线时,该哨兵节点需要通过“sentinel is-master-down-by addr”命令向其他节点咨询主节点是否下线了,如果超过半数哨兵节点认为主节点已经下线了,此时认为主节点“客观下线”。

 

选举哨兵领导者:

       当主节点客观下线时,需要选举出一个哨兵节点作为领导者,已完成后续选择出的新的主节点的工作。

选举的大致思路是

  1. 每个哨兵节点是通过向其他节点发送“sentinel is-master-down-by addr”命令来哨兵领导者。
  2. 而每个哨兵节点再收到一个“sentinel is-master-down-by addr”命令之时,只允许给第一个节点投票,其他节点的该命令都会被拒绝。
  3. 如果一个哨兵节点收到半数以上的同意票,则成为哨兵领导节点。
  4. 如果前三步在一定时间内都没有选出一个哨兵领导者,将 重新开始下一次选举。

无量虚空神主注:这段我有点糊涂,所以在官方文档翻译了这段(SENTINEL get-master-addr-by-name <master name>  返回给定名字的主服务器的 IP 地址和端口号。 如果这个主服务器正在执行故障转移操作, 或者针对这个主服务器的故障转移操作已经完成, 那么这个命令返回新的主服务器的 IP 地址和端口号。

可以看出,这个选举领导者的流程很像Raft中选举Leader的流程。

选出新的节点:

在剩下的Redis从节点中,按照以下顺序选出新的主节点:

  1. 过滤掉“不健康”的数据节点:比如主观下线、断线的从节点、五秒内没有回复过哨兵节点ping命令(心跳反应)的节点、与主节点失联的从节点。
  2. 选择slave-priority(从节点优先级)最高的节点,如果存在则返回,如果不存在则继续后面的流程。
  3. 到了这里,所有从节点的状态都是一样的,选择runid最小的节点。

提升新的主节点:

选择新的主节点之后,还需要最后的流程让该节点成为新的主节点:

  1. 哨兵领导者向上一步选出的从节点发出”slaveof no one”命令,让该节点成为主节点;
  • 哨兵领导者向剩余的从节点发送命令,让它们成为新主节点的从节点。(failover-state-send-slaveof-noone <instance details> Sentinel 正在将指定的从服务器升级为主服务器,等待升级功能完成。)
  1. 哨兵节点会将原来的主节点更新为从节点,当其恢复之后,会命令它去复制新主节点的数据。

无量虚空神主注:另外附上官方文档地址,希望大家可以多读源文档。

官方文档:https://redis.io/documentation

这是中文翻译比较好的http://redisdoc.com/

    

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章