构建高可用的Redis服务(主从复制/哨兵/集群底层原理)

Posted 白龙码~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构建高可用的Redis服务(主从复制/哨兵/集群底层原理)相关的知识,希望对你有一定的参考价值。

文章目录

高可用的Redis服务

高可用:常见于分布式系统,指通过系统设计使能够提供服务的时间达到较高值。

若系统能一直运行,则可用性为100%。

Redis为了高可用,提供了三种保障机制。

一、主从复制

在Redis中,可以通过slaveof命令让一个Redis服务复制另一个Redis服务,我们称呼被复制的服务器为"主服务器",对主服务器进行复制的称为"从服务器"。

复制分为两部分:同步与命令传播。

  • 同步:将从服务器的状态更新至主服务器的状态,即拥有相同数据。
  • 命令传播:当客户端命令使主服务器状态改变时,主服务器向从服务器发送对应命令,更新从服务器的数据。

心跳检测:命令传播阶段,从服务器每秒一次向主服务器发送特定的命令,检测当前网络连接状态以及命令是否丢失等。

1、主从复制的底层原理

I. 完整同步

完整同步用来处理初次将主服务器数据同步到从服务器中,步骤如下:

  1. 从服务器向主服务器发送sync命令请求同步数据。
  2. 主服务器收到sync后执行bgsave,生成RDB文件,同时将生成文件期间收到的写命令存入一个缓冲区中。
  3. 主服务器将RDB文件发送至从服务器,从服务器接收后进行数据载入。
  4. 主服务器将缓冲区中的命令发送给从服务器,从服务器接收后进行数据写入。

至此,完整同步部分就完成了。此后,主服务器通过命令传播实时更新从服务器的状态。


II. 部分同步

部分同步用于从服务器断线后重新复制数据的情况。

  • 对于Redis 2.8之前的版本,从服务器会重新进行一次完整同步,但是这样的缺点就是效率太低,而且从服务器本地还存有大部分的持久化的数据,只因为部分数据的丢失而进行完整同步是没有必要的。
  • 对于Redis 2.8之后的版本,Redis重写了同步函数,用psync代替sync,解决了之前版本部分重同步低效的问题。
psync实现原理
  1. 复制偏移量

    主从服务器各自维护一个复制偏移量:主服务器发送N字节数据时,就将自己的复制偏移量加N;从服务器收到N字节数据时,就将自己的复制偏移量加N。

    如果发生断线,则从服务器只需要复制自身偏移量之后的数据即可。

  2. 复制积压缓冲区

    复制积压缓冲区是主服务器维护的一个FIFO队列,默认大小为1MB,队列中保存着命令和对应的偏移量。

    • 如果从服务器请求的偏移量之后的数据还在队列,则主服务器利用这部分数据执行从服务器的部分重同步
    • 如果从服务器请求的偏移量之后的数据不在队列,则主服务器直接执行从服务器的完整同步
  3. 服务器运行ID

    Redis服务器在启动时自动生成40个十六进制字符组成的随机运行ID。

    从服务器在初次复制主服务器时,会将主服务器的运行ID保存下来。

    • 当从服务器断线重连时,发现此时的主服务器依然是上一次的主服务器,则执行部分同步
    • 当从服务器断线重连时,发现此时的主服务器不再是上一次的主服务器,则执行完整同步

2、主从复制的优缺点

优点:

  1. 能够实现读写分离,主服务器用于写,其它从服务器用来读,从而提高性能
  2. 数据更加安全:做了数据冗余,不会因为某一台服务器宕机而丢失全部数据

缺点:

  1. 同步操作在系统繁忙时会有相当大的延迟,从而导致数据不一致的情况。
  2. 无法降低主服务器的写压力。

二、哨兵

哨兵(Sentinel)是一个分布式架构,包含一个或多个哨兵实例,可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器。

哨兵实例本质上是利用redis-centinel+配置文件启动的特殊类型Redis服务器,不存储数据,只支持部分Redis命令。不同哨兵之间可以进行信息交互。

1、工作模式

  1. 每个哨兵以每秒一次的频率向主、从服务器发送PING命令,通过回复来判断对应服务器是否在线。「监控」

    若距离上一次收到有效响应的时间超出配置文件中的down-after-milliseconds ,则哨兵可以主观判定该服务器下线

    注:PING的有效回复包括"+PONG"、“-LOADING”、“-MASTERDOWN”

  2. 当一个哨兵主观判定某个主服务器下线后,它会向同样监视该主服务器的其它哨兵询问,看它们是否也主观认为该服务器下线。

    如果接收到一定数量的"已下线"判断,Sentinel就会将该主服务器判定为**“客观下线”,这样做可以尽可能防止误判**。

    注:具体需要多少个"已下线"判断由每个哨兵的配置文件决定,该数量被保存在哨兵实例的quorum成员变量中。

  3. 从监视该下线主服务器的哨兵中选出一个领头哨兵,由领头哨兵选出优先级最高的从服务器,让它作为新的主服务器。若优先级相同,则选出运行ID最小的,即创建时间最早的。「故障转移」

    注:服务器优先级可以通过配置文件中的replica-priority设置,值越小,优先级越高。

  4. 如果原先的主服务器重新上线,那么它会成为现在这个新主服务器的从服务器

2、哨兵的优缺点

优点:

  1. 继承了主从复制的所有优点,可以做到读写分离、保障数据不会大量丢失
  2. 自动进行故障转移,用户友好

缺点:

  1. 配置麻烦。
  2. 故障转移时可能导致服务较长时间不可用。

三、集群

集群(Cluster):通过分片来进行数据共享,提供复制和故障转移功能。

一个集群通常由多个节点组成,每个节点相互独立,节点内有一个主机和多个从机。

注:启动集群节点客户端需要-c选项,如redis-cli -c -p xxxx

1、集群的配置

  1. 启动节点

    集群的每个节点都是一个Redis服务器,启动该服务器前需要将配置文件的cluster-enabled选项置为yes。

  2. 连接节点

    集群的每个节点都是一个clusterNode结构,节点之间通过CLUSTER MEET ip:port命令进行连接。以节点A连接节点B为例:

    • 节点A创建并维护一个节点B的clusterNode结构,同时向节点B发送一个MEET消息。
    • 节点B收到消息后创建并维护一个节点A的clusterNode结构,同时向节点A发送一个PONG消息。
    • 节点A向节点B发送PING消息,完成==“三次握手”==。
    • 最后,通过相同的方式,将节点B与节点A所在集群的其它节点建立连接。
  3. 指派槽位(分片)

    集群的整个数据库被分为16384个槽(slot),而用户需要在指定客户端下通过CLUSTER ADDSLOTS slot [slot1 slot2 ...]进行槽的分配,例如:使用CLUSTER ADDSLOTS 0 1 2 3 ... 5000将槽0~5000分配给客户端连接的那个节点服务器。每个节点负责了哪些槽最终都会被同步到集群的各个节点中,存储在每个节点的clusterNode *slots[16384]数组中。

    插入到数据库中的键通过CRC校验和计算一个0~16383之间数,从而确定它的槽,计算公式为slot=CRC16(key)&16383

    • 如果键所在的槽由当前节点负责,那么当前节点直接执行该命令。
    • 如果键所在的槽由其他节点负责,那么当前节点通过slots数组迅速定位到负责该槽的节点,并向客户端返回MOVED错误,客户端收到后会自动将命令转交给对方
  4. 复制与故障转移

    集群中的节点可以通过CLUSTER REPLICATE <节点运行时id>将当前节点设置为id对应节点的从节点,实现主从复制。

    集群中的每个节点都扮演了哨兵的角色。当某个节点疑似下线时,它们通过投票的方式判断该节点是否客观下线,如果是,则进行故障转移,选取新的从机作为节点的主机。

2、集群的优缺点

优点:

  1. 集群缓解了单主机模式下的写压力。
  2. 数据可以存储在不同的节点,缓解了海量数据存储的压力。

缺点:

  1. 不支持多键值插入,除非保证它们映射在同一节点的槽中。
  2. 数据通过异步复制,不保证数据的强一致性

以上是关于构建高可用的Redis服务(主从复制/哨兵/集群底层原理)的主要内容,如果未能解决你的问题,请参考以下文章

高可用集群架构——redis的主从复制与哨兵模式,cluster

redis高可用之主从复制,哨兵,集群

Redis高可用集群方案(主从复制,哨兵模式,Redis集群)

Redis集群模式1-主从复制+哨兵机制

玩转Redis的高可用(主从、哨兵、集群)

Redis 高可用方案 主从及哨兵